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.eclipse.jdt.annotation.Nullable;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
27 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
28 import org.opendaylight.genius.infra.Datastore.Configuration;
29 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
30 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
31 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
32 import org.opendaylight.genius.mdsalutil.ActionInfo;
33 import org.opendaylight.genius.mdsalutil.FlowEntity;
34 import org.opendaylight.genius.mdsalutil.InstructionInfo;
35 import org.opendaylight.genius.mdsalutil.MDSALUtil;
36 import org.opendaylight.genius.mdsalutil.MatchInfo;
37 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
38 import org.opendaylight.genius.mdsalutil.NwConstants;
39 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
40 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
41 import org.opendaylight.genius.mdsalutil.actions.ActionSetDestinationIp;
42 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
43 import org.opendaylight.genius.mdsalutil.actions.ActionSetSourceIp;
44 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
45 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
46 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
47 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
48 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
49 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
50 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
51 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Source;
52 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
53 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
54 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
55 import org.opendaylight.netvirt.natservice.api.CentralizedSwitchScheduler;
56 import org.opendaylight.netvirt.natservice.api.NatSwitchCache;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.FloatingIpInfo;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapKey;
72 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
77 public class FloatingIPListener extends AsyncDataTreeChangeListenerBase<InternalToExternalPortMap, FloatingIPListener> {
78 private static final Logger LOG = LoggerFactory.getLogger(FloatingIPListener.class);
79 private final DataBroker dataBroker;
80 private final ManagedNewTransactionRunner txRunner;
81 private final IMdsalApiManager mdsalManager;
82 private final OdlInterfaceRpcService interfaceManager;
83 private final FloatingIPHandler floatingIPHandler;
84 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
85 private final JobCoordinator coordinator;
86 private final CentralizedSwitchScheduler centralizedSwitchScheduler;
87 private final NatSwitchCache natSwitchCache;
90 public FloatingIPListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
91 final OdlInterfaceRpcService interfaceManager,
92 final FloatingIPHandler floatingIPHandler,
93 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
94 final JobCoordinator coordinator,
95 final CentralizedSwitchScheduler centralizedSwitchScheduler,
96 final NatSwitchCache natSwitchCache) {
97 super(InternalToExternalPortMap.class, FloatingIPListener.class);
98 this.dataBroker = dataBroker;
99 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
100 this.mdsalManager = mdsalManager;
101 this.interfaceManager = interfaceManager;
102 this.floatingIPHandler = floatingIPHandler;
103 this.defaultRouteProgrammer = snatDefaultRouteProgrammer;
104 this.coordinator = coordinator;
105 this.centralizedSwitchScheduler = centralizedSwitchScheduler;
106 this.natSwitchCache = natSwitchCache;
112 LOG.info("{} init", getClass().getSimpleName());
113 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
117 protected InstanceIdentifier<InternalToExternalPortMap> getWildCardPath() {
118 return InstanceIdentifier.create(FloatingIpInfo.class).child(RouterPorts.class).child(Ports.class)
119 .child(InternalToExternalPortMap.class);
123 protected FloatingIPListener getDataTreeChangeListener() {
124 return FloatingIPListener.this;
128 protected void add(final InstanceIdentifier<InternalToExternalPortMap> identifier,
129 final InternalToExternalPortMap mapping) {
130 LOG.trace("FloatingIPListener add ip mapping method - key: {} value: {}",mapping.key(), mapping);
131 processFloatingIPAdd(identifier, mapping);
135 protected void remove(InstanceIdentifier<InternalToExternalPortMap> identifier, InternalToExternalPortMap mapping) {
136 LOG.trace("FloatingIPListener remove ip mapping method - kkey: {} value: {}",mapping.key(), mapping);
137 processFloatingIPDel(identifier, mapping);
141 protected void update(InstanceIdentifier<InternalToExternalPortMap> identifier, InternalToExternalPortMap
142 original, InternalToExternalPortMap update) {
143 LOG.trace("FloatingIPListener update ip mapping method - key: {}, original: {}, update: {}",
144 update.key(), original, update);
148 private FlowEntity buildPreDNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long routerId, long
150 String externalIp = mapping.getExternalIp();
151 Uuid floatingIpId = mapping.getExternalId();
152 //Get the FIP MAC address for DNAT
153 String floatingIpPortMacAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
154 if (floatingIpPortMacAddress == null) {
155 LOG.error("buildPreDNATFlowEntity : Unable to retrieve floatingIpPortMacAddress from floating IP UUID {} "
156 + "for floating IP {}", floatingIpId, externalIp);
159 LOG.debug("buildPreDNATFlowEntity : Bulding DNAT Flow entity for ip {} ", externalIp);
160 long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
161 LOG.debug("buildPreDNATFlowEntity : Segment id {} in build preDNAT Flow", segmentId);
163 List<MatchInfo> matches = new ArrayList<>();
164 matches.add(MatchEthernetType.IPV4);
166 matches.add(new MatchIpv4Destination(externalIp, "32"));
167 //Match Destination Floating IP MAC Address on table = 25 (PDNAT_TABLE)
168 matches.add(new MatchEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
170 // matches.add(new MatchMetadata(
171 // BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
172 List<ActionInfo> actionsInfos = new ArrayList<>();
173 String internalIp = mapping.getInternalIp();
174 actionsInfos.add(new ActionSetDestinationIp(internalIp, "32"));
176 List<InstructionInfo> instructions = new ArrayList<>();
177 instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(segmentId),
178 MetaDataUtil.METADATA_MASK_VRFID));
179 instructions.add(new InstructionApplyActions(actionsInfos));
180 instructions.add(new InstructionGotoTable(NwConstants.DNAT_TABLE));
182 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PDNAT_TABLE, routerId, externalIp);
184 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PDNAT_TABLE, flowRef,
185 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
186 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
191 private FlowEntity buildDNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long routerId, long
193 String externalIp = mapping.getExternalIp();
194 LOG.info("buildDNATFlowEntity : Bulding DNAT Flow entity for ip {} ", externalIp);
196 long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
197 LOG.debug("buildDNATFlowEntity : Segment id {} in build DNAT", segmentId);
199 List<MatchInfo> matches = new ArrayList<>();
200 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
202 matches.add(MatchEthernetType.IPV4);
203 String internalIp = mapping.getInternalIp();
204 matches.add(new MatchIpv4Destination(internalIp, "32"));
206 List<ActionInfo> actionsInfos = new ArrayList<>();
207 // actionsInfos.add(new ActionSetDestinationIp(internalIp, "32"));
209 List<InstructionInfo> instructions = new ArrayList<>();
210 // instructions.add(new InstructionWriteMetadata(BigInteger.valueOf
211 // (routerId), MetaDataUtil.METADATA_MASK_VRFID));
212 actionsInfos.add(new ActionNxLoadInPort(BigInteger.ZERO));
213 actionsInfos.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
214 instructions.add(new InstructionApplyActions(actionsInfos));
215 //instructions.add(new InstructionGotoTable(NatConstants.L3_FIB_TABLE));
217 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.DNAT_TABLE, routerId, internalIp);
219 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DNAT_TABLE, flowRef,
220 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
221 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
227 private FlowEntity buildPreSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, long
228 routerId, long associatedVpn) {
230 LOG.debug("buildPreSNATFlowEntity : Building PSNAT Flow entity for ip {} ", internalIp);
232 long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
234 LOG.debug("buildPreSNATFlowEntity : Segment id {} in build preSNAT flow", segmentId);
236 List<MatchInfo> matches = new ArrayList<>();
237 matches.add(MatchEthernetType.IPV4);
239 matches.add(new MatchIpv4Source(internalIp, "32"));
241 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
243 List<ActionInfo> actionsInfos = new ArrayList<>();
244 actionsInfos.add(new ActionSetSourceIp(externalIp, "32"));
246 List<InstructionInfo> instructions = new ArrayList<>();
248 new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
249 instructions.add(new InstructionApplyActions(actionsInfos));
250 instructions.add(new InstructionGotoTable(NwConstants.SNAT_TABLE));
252 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PSNAT_TABLE, routerId, internalIp);
254 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
255 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
256 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
262 private FlowEntity buildSNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long vpnId, Uuid
264 String internalIp = mapping.getInternalIp();
265 LOG.debug("buildSNATFlowEntity : Building SNAT Flow entity for ip {} ", internalIp);
267 ProviderTypes provType = NatUtil.getProviderTypefromNetworkId(dataBroker, externalNetworkId);
268 if (provType == null) {
269 LOG.error("buildSNATFlowEntity : Unable to get Network Provider Type for network {}", externalNetworkId);
273 List<MatchInfo> matches = new ArrayList<>();
274 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
275 matches.add(MatchEthernetType.IPV4);
276 String externalIp = mapping.getExternalIp();
277 matches.add(new MatchIpv4Source(externalIp, "32"));
279 List<ActionInfo> actionsInfo = new ArrayList<>();
280 actionsInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
281 Uuid floatingIpId = mapping.getExternalId();
282 String macAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
283 if (macAddress != null) {
284 actionsInfo.add(new ActionSetFieldEthernetSource(new MacAddress(macAddress)));
286 LOG.warn("buildSNATFlowEntity : No MAC address found for floating IP {}", externalIp);
289 LOG.trace("buildSNATFlowEntity : External Network Provider Type is {}, resubmit to FIB", provType.toString());
290 actionsInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
291 List<InstructionInfo> instructions = new ArrayList<>();
292 instructions.add(new InstructionApplyActions(actionsInfo));
293 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.SNAT_TABLE, vpnId, externalIp);
295 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.SNAT_TABLE, flowRef,
296 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
297 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
303 private void createDNATTblEntry(BigInteger dpnId, InternalToExternalPortMap mapping, long routerId,
304 long associatedVpnId, TypedReadWriteTransaction<Configuration> confTx) {
305 FlowEntity preFlowEntity = buildPreDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
306 if (preFlowEntity == null) {
307 LOG.error("createDNATTblEntry : Flow entity received as NULL. "
308 + "Cannot proceed with installation of Pre-DNAT flow table {} --> table {} on DpnId {}",
309 NwConstants.PDNAT_TABLE, NwConstants.DNAT_TABLE, dpnId);
311 mdsalManager.addFlow(confTx, preFlowEntity);
312 FlowEntity flowEntity = buildDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
313 if (flowEntity != null) {
314 mdsalManager.addFlow(confTx, flowEntity);
319 private void removeDNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId,
320 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
321 FlowEntity preFlowEntity = buildPreDNATDeleteFlowEntity(dpnId, externalIp, routerId);
322 mdsalManager.removeFlow(confTx, preFlowEntity);
324 FlowEntity flowEntity = buildDNATDeleteFlowEntity(dpnId, internalIp, routerId);
325 if (flowEntity != null) {
326 mdsalManager.removeFlow(confTx, flowEntity);
330 private void createSNATTblEntry(BigInteger dpnId, InternalToExternalPortMap mapping, long vpnId, long routerId,
331 long associatedVpnId, Uuid externalNetworkId, TypedReadWriteTransaction<Configuration> confTx) {
332 FlowEntity preFlowEntity = buildPreSNATFlowEntity(dpnId, mapping.getInternalIp(), mapping.getExternalIp(),
333 vpnId, routerId, associatedVpnId);
334 mdsalManager.addFlow(confTx, preFlowEntity);
336 FlowEntity flowEntity = buildSNATFlowEntity(dpnId, mapping, vpnId, externalNetworkId);
337 if (flowEntity != null) {
338 mdsalManager.addFlow(confTx, flowEntity);
342 private void removeSNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId, long vpnId,
343 TypedReadWriteTransaction<Configuration> removeFlowInvTx)
344 throws ExecutionException, InterruptedException {
345 FlowEntity preFlowEntity = buildPreSNATDeleteFlowEntity(dpnId, internalIp, routerId);
346 mdsalManager.removeFlow(removeFlowInvTx, preFlowEntity);
348 FlowEntity flowEntity = buildSNATDeleteFlowEntity(dpnId, externalIp, vpnId);
349 if (flowEntity != null) {
350 mdsalManager.removeFlow(removeFlowInvTx, flowEntity);
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 return rtrPort.get().getExternalNetworkId();
368 private long getVpnId(Uuid extNwId, Uuid floatingIpExternalId) {
369 Uuid subnetId = NatUtil.getFloatingIpPortSubnetIdFromFloatingIpId(dataBroker, floatingIpExternalId);
370 if (subnetId != null) {
371 long vpnId = NatUtil.getVpnId(dataBroker, subnetId.getValue());
372 if (vpnId != NatConstants.INVALID_ID) {
373 LOG.debug("getVpnId : Got vpnId {} for floatingIpExternalId {}", vpnId, floatingIpExternalId);
378 InstanceIdentifier<Networks> nwId = InstanceIdentifier.builder(ExternalNetworks.class).child(Networks.class,
379 new NetworksKey(extNwId)).build();
380 Optional<Networks> nw =
381 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
382 LogicalDatastoreType.CONFIGURATION, nwId);
383 if (!nw.isPresent()) {
384 LOG.error("getVpnId : Unable to read external network for {}", extNwId);
385 return NatConstants.INVALID_ID;
388 Uuid vpnUuid = nw.get().getVpnid();
389 if (vpnUuid == null) {
390 LOG.error("getVpnId : Unable to read vpn from External network: {}", extNwId);
391 return NatConstants.INVALID_ID;
394 //Get the id using the VPN UUID (also vpn instance name)
395 return NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
398 private void processFloatingIPAdd(final InstanceIdentifier<InternalToExternalPortMap> identifier,
399 final InternalToExternalPortMap mapping) {
400 LOG.trace("processFloatingIPAdd key: {}, value: {}", mapping.key(), mapping);
402 final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
403 final PortsKey pKey = identifier.firstKeyOf(Ports.class);
404 String interfaceName = pKey.getPortName();
406 InstanceIdentifier<RouterPorts> portIid = identifier.firstIdentifierOf(RouterPorts.class);
407 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + mapping.key(), () -> Collections.singletonList(
408 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
409 tx -> createNATFlowEntries(interfaceName, mapping, portIid, routerId, null, tx))),
410 NatConstants.NAT_DJC_MAX_RETRIES);
413 private void processFloatingIPDel(final InstanceIdentifier<InternalToExternalPortMap> identifier,
414 final InternalToExternalPortMap mapping) {
415 LOG.trace("processFloatingIPDel : key: {}, value: {}", mapping.key(), mapping);
417 final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
418 final PortsKey pKey = identifier.firstKeyOf(Ports.class);
419 String interfaceName = pKey.getPortName();
421 InstanceIdentifier<RouterPorts> portIid = identifier.firstIdentifierOf(RouterPorts.class);
422 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + mapping.key(), () -> Collections.singletonList(
423 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
424 tx -> removeNATFlowEntries(interfaceName, mapping, portIid, routerId, null, tx))),
425 NatConstants.NAT_DJC_MAX_RETRIES);
428 private InetAddress getInetAddress(String ipAddr) {
429 InetAddress ipAddress = null;
431 ipAddress = InetAddress.getByName(ipAddr);
432 } catch (UnknownHostException e) {
433 LOG.error("getInetAddress : UnknowHostException for ip {}", ipAddr, e);
438 private boolean validateIpMapping(InternalToExternalPortMap mapping) {
439 return getInetAddress(mapping.getInternalIp()) != null && getInetAddress(mapping.getExternalIp()) != null;
442 private BigInteger getAssociatedDpnWithExternalInterface(final String routerName, Uuid extNwId, BigInteger dpnId,
443 String interfaceName) {
444 //Get the DPN on which this interface resides
446 dpnId = NatUtil.getDpnForInterface(interfaceManager, interfaceName);
448 BigInteger updatedDpnId = dpnId;
449 if (updatedDpnId.equals(BigInteger.ZERO)) {
450 LOG.debug("getAssociatedDpnWithExternalInterface : The interface {} is not associated with any dpn",
454 ProviderTypes providerType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNwId);
455 if (providerType == null) {
456 LOG.warn("getAssociatedDpnWithExternalInterface : Provider Network Type for router {} and"
457 + " externalNetwork {} is missing.", routerName, extNwId);
461 // For FLAT and VLAN provider networks, we have to ensure that dpn hosting the VM has connectivity
462 // to External Network via provider_mappings. In case the dpn does not have the provider mappings,
463 // traffic from the VM has to be forwarded to the NAPT Switch (which is scheduled based on the provider
464 // mappings) and then sent out on the external Network.
465 if (providerType == ProviderTypes.FLAT || providerType == ProviderTypes.VLAN) {
466 String providerNet = NatUtil.getElanInstancePhysicalNetwok(extNwId.getValue(), dataBroker);
467 boolean isDpnConnected = natSwitchCache.isSwitchConnectedToExternal(updatedDpnId, providerNet);
468 if (!isDpnConnected) {
469 updatedDpnId = centralizedSwitchScheduler.getCentralizedSwitch(routerName);
475 void createNATFlowEntries(String interfaceName, final InternalToExternalPortMap mapping,
476 final InstanceIdentifier<RouterPorts> portIid, final String routerName, @Nullable BigInteger dpnId,
477 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
478 if (!validateIpMapping(mapping)) {
479 LOG.error("createNATFlowEntries : Not a valid ip addresses in the mapping {}", mapping);
483 Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.CONFIGURATION);
484 if (extNwId == null) {
485 LOG.error("createNATFlowEntries : External network associated with interface {} could not be retrieved",
490 // For Overlay Networks, get the DPN on which this interface resides.
491 // For FLAT/VLAN Networks, get the DPN with provider_mappings for external network.
492 dpnId = getAssociatedDpnWithExternalInterface(routerName, extNwId, dpnId, interfaceName);
493 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
494 LOG.warn("createNATFlowEntries : No DPN for interface {}. NAT flow entries for ip mapping {} will "
495 + "not be installed", interfaceName, mapping);
499 long routerId = NatUtil.getVpnId(dataBroker, routerName);
500 if (routerId == NatConstants.INVALID_ID) {
501 LOG.error("createNATFlowEntries : Could not retrieve router id for {} to create NAT Flow entries",
505 //Check if the router to vpn association is present
506 //long associatedVpnId = NatUtil.getAssociatedVpn(dataBroker, routerName);
507 Uuid associatedVpn = NatUtil.getVpnForRouter(dataBroker, routerName);
508 long associatedVpnId = NatConstants.INVALID_ID;
509 if (associatedVpn == null) {
510 LOG.debug("createNATFlowEntries : Router {} is not assicated with any BGP VPN instance", routerName);
512 LOG.debug("createNATFlowEntries : Router {} is associated with VPN Instance with Id {}",
513 routerName, associatedVpn);
514 associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVpn.getValue());
515 LOG.debug("createNATFlowEntries : vpninstance Id is {} for VPN {}", associatedVpnId, associatedVpn);
516 //routerId = associatedVpnId;
519 long vpnId = getVpnId(extNwId, mapping.getExternalId());
521 LOG.error("createNATFlowEntries : No VPN associated with Ext nw {}. Unable to create SNAT table entry "
522 + "for fixed ip {}", extNwId, mapping.getInternalIp());
525 //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
526 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
527 if (!isSnatEnabled) {
528 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, true);
530 //Create the DNAT and SNAT table entries
531 createDNATTblEntry(dpnId, mapping, routerId, associatedVpnId, confTx);
532 createSNATTblEntry(dpnId, mapping, vpnId, routerId, associatedVpnId, extNwId, confTx);
533 floatingIPHandler.onAddFloatingIp(dpnId, routerName, routerId, extNwId, interfaceName, mapping, confTx);
536 void createNATFlowEntries(BigInteger dpnId, String interfaceName, String routerName, Uuid externalNetworkId,
537 InternalToExternalPortMap mapping, TypedReadWriteTransaction<Configuration> confTx)
538 throws ExecutionException, InterruptedException {
539 String internalIp = mapping.getInternalIp();
540 long routerId = NatUtil.getVpnId(dataBroker, routerName);
541 if (routerId == NatConstants.INVALID_ID) {
542 LOG.error("createNATFlowEntries : Could not retrieve router id for {} to create NAT Flow entries",
546 //Check if the router to vpn association is present
547 long associatedVpnId = NatUtil.getAssociatedVpn(dataBroker, routerName);
548 if (associatedVpnId == NatConstants.INVALID_ID) {
549 LOG.debug("createNATFlowEntries : Router {} is not assicated with any BGP VPN instance", routerName);
551 LOG.debug("createNATFlowEntries : Router {} is associated with VPN Instance with Id {}",
552 routerName, associatedVpnId);
553 //routerId = associatedVpnId;
556 long vpnId = getVpnId(externalNetworkId, mapping.getExternalId());
558 LOG.error("createNATFlowEntries : Unable to create SNAT table entry for fixed ip {}", internalIp);
561 //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
562 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
563 if (!isSnatEnabled) {
564 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, true);
566 //Create the DNAT and SNAT table entries
567 createDNATTblEntry(dpnId, mapping, routerId, associatedVpnId, confTx);
568 createSNATTblEntry(dpnId, mapping, vpnId, routerId, associatedVpnId, externalNetworkId, confTx);
569 floatingIPHandler.onAddFloatingIp(dpnId, routerName, routerId, externalNetworkId, interfaceName, mapping,
573 void createNATOnlyFlowEntries(BigInteger dpnId, String routerName, @Nullable String associatedVPN,
574 Uuid externalNetworkId, InternalToExternalPortMap mapping)
575 throws ExecutionException, InterruptedException {
576 String internalIp = mapping.getInternalIp();
577 //String segmentId = associatedVPN == null ? routerName : associatedVPN;
578 LOG.debug("createNATOnlyFlowEntries : Retrieving vpn id for VPN {} to proceed with create NAT Flows",
580 long routerId = NatUtil.getVpnId(dataBroker, routerName);
581 if (routerId == NatConstants.INVALID_ID) {
582 LOG.error("createNATOnlyFlowEntries : Could not retrieve vpn id for {} to create NAT Flow entries",
586 long associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVPN);
587 LOG.debug("createNATOnlyFlowEntries : Associated VPN Id {} for router {}", associatedVpnId, routerName);
588 long vpnId = getVpnId(externalNetworkId, mapping.getExternalId());
590 LOG.error("createNATOnlyFlowEntries : Unable to create SNAT table entry for fixed ip {}", internalIp);
593 //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
594 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
595 if (!isSnatEnabled) {
596 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, null, true);
598 //Create the DNAT and SNAT table entries
599 FlowEntity preFlowEntity = buildPreDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
600 mdsalManager.installFlow(preFlowEntity);
602 FlowEntity flowEntity = buildDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
603 mdsalManager.installFlow(flowEntity);
605 String externalIp = mapping.getExternalIp();
606 preFlowEntity = buildPreSNATFlowEntity(dpnId, internalIp, externalIp, vpnId , routerId, associatedVpnId);
607 mdsalManager.installFlow(preFlowEntity);
609 flowEntity = buildSNATFlowEntity(dpnId, mapping, vpnId, externalNetworkId);
610 if (flowEntity != null) {
611 mdsalManager.installFlow(flowEntity);
616 void removeNATFlowEntries(String interfaceName, final InternalToExternalPortMap mapping,
617 InstanceIdentifier<RouterPorts> portIid, final String routerName, @Nullable BigInteger dpnId,
618 TypedReadWriteTransaction<Configuration> removeFlowInvTx) throws ExecutionException, InterruptedException {
619 Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.OPERATIONAL);
620 if (extNwId == null) {
621 LOG.error("removeNATFlowEntries : External network associated with interface {} could not be retrieved",
626 // For Overlay Networks, get the DPN on which this interface resides.
627 // For FLAT/VLAN Networks, get the DPN with provider_mappings for external network.
629 dpnId = getAssociatedDpnWithExternalInterface(routerName, extNwId,
630 NatUtil.getDpnForInterface(interfaceManager, interfaceName), interfaceName);
631 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
632 LOG.warn("removeNATFlowEntries: Abort processing Floating ip configuration. No DPN for port: {}",
638 long routerId = NatUtil.getVpnId(dataBroker, routerName);
639 if (routerId == NatConstants.INVALID_ID) {
640 LOG.error("removeNATFlowEntries : Could not retrieve router id for {} to remove NAT Flow entries",
645 String internalIp = mapping.getInternalIp();
646 String externalIp = mapping.getExternalIp();
648 //Delete the DNAT and SNAT table entries
649 removeDNATTblEntry(dpnId, internalIp, externalIp, routerId, removeFlowInvTx);
651 long vpnId = getVpnId(extNwId, mapping.getExternalId());
653 LOG.error("removeNATFlowEntries : No VPN associated with ext nw {}. Unable to delete SNAT table "
654 + "entry for fixed ip {}", extNwId, internalIp);
657 removeSNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, removeFlowInvTx);
658 //Remove the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
659 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
660 if (!isSnatEnabled) {
661 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, removeFlowInvTx, false);
663 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNwId);
664 if (provType == null) {
665 LOG.error("removeNATFlowEntries : External Network Provider Type missing");
668 if (provType == ProviderTypes.VXLAN) {
669 floatingIPHandler.onRemoveFloatingIp(dpnId, routerName, routerId, extNwId, mapping,
670 NatConstants.DEFAULT_L3VNI_VALUE, removeFlowInvTx);
671 removeOperationalDS(routerName, interfaceName, internalIp);
674 long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
676 LOG.error("removeNATFlowEntries : Could not retrieve label for prefix {} in router {}",
677 internalIp, routerId);
680 floatingIPHandler.onRemoveFloatingIp(dpnId, routerName, routerId, extNwId, mapping, (int) label,
682 removeOperationalDS(routerName, interfaceName, internalIp);
685 void removeNATFlowEntries(BigInteger dpnId, String interfaceName, String vpnName, String routerName,
686 InternalToExternalPortMap mapping, TypedReadWriteTransaction<Configuration> confTx)
687 throws ExecutionException, InterruptedException {
688 String internalIp = mapping.getInternalIp();
689 String externalIp = mapping.getExternalIp();
690 long routerId = NatUtil.getVpnId(dataBroker, routerName);
691 if (routerId == NatConstants.INVALID_ID) {
692 LOG.error("removeNATFlowEntries : Could not retrieve router id for {} to remove NAT Flow entries",
697 long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
698 if (vpnId == NatConstants.INVALID_ID) {
699 LOG.warn("removeNATFlowEntries : VPN Id not found for {} to remove NAT flow entries {}",
700 vpnName, internalIp);
703 //Delete the DNAT and SNAT table entries
704 removeDNATTblEntry(dpnId, internalIp, externalIp, routerId, confTx);
705 removeSNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, confTx);
706 //Remove the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
707 boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
708 if (!isSnatEnabled) {
709 addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, false);
711 Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
712 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, externalNetworkId);
713 if (provType == null) {
714 LOG.error("removeNATFlowEntries : External Network Provider Type Missing");
717 if (provType == ProviderTypes.VXLAN) {
718 floatingIPHandler.cleanupFibEntries(dpnId, vpnName, externalIp, NatConstants.DEFAULT_L3VNI_VALUE,
720 removeOperationalDS(routerName, interfaceName, internalIp);
723 long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
725 LOG.error("removeNATFlowEntries : Could not retrieve label for prefix {} in router {}",
726 internalIp, routerId);
729 floatingIPHandler.cleanupFibEntries(dpnId, vpnName, externalIp, label, confTx, provType);
730 removeOperationalDS(routerName, interfaceName, internalIp);
733 protected long getOperationalIpMapping(String routerId, String interfaceName, String internalIp) {
734 InstanceIdentifier<InternalToExternalPortMap> intExtPortMapIdentifier =
735 NatUtil.getIntExtPortMapIdentifier(routerId, interfaceName, internalIp);
736 return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
737 LogicalDatastoreType.OPERATIONAL, intExtPortMapIdentifier).toJavaUtil().map(
738 InternalToExternalPortMap::getLabel).orElse(NatConstants.INVALID_ID);
741 static void updateOperationalDS(DataBroker dataBroker, String routerId, String interfaceName, long label,
742 String internalIp, String externalIp) {
744 LOG.info("updateOperationalDS : Updating operational DS for floating ip config : {} with label {}",
746 InstanceIdentifier<Ports> portsId = NatUtil.getPortsIdentifier(routerId, interfaceName);
747 Optional<Ports> optPorts =
748 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
749 LogicalDatastoreType.OPERATIONAL, portsId);
750 InternalToExternalPortMap intExtPortMap = new InternalToExternalPortMapBuilder().withKey(new
751 InternalToExternalPortMapKey(internalIp)).setInternalIp(internalIp).setExternalIp(externalIp)
752 .setLabel(label).build();
753 if (optPorts.isPresent()) {
754 LOG.debug("updateOperationalDS : Ports {} entry already present. Updating intExtPortMap for internal ip {}",
755 interfaceName, internalIp);
756 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, portsId.child(InternalToExternalPortMap
757 .class, new InternalToExternalPortMapKey(internalIp)), intExtPortMap);
759 LOG.debug("updateOperationalDS : Adding Ports entry {} along with intExtPortMap {}",
760 interfaceName, internalIp);
761 List<InternalToExternalPortMap> intExtPortMapList = new ArrayList<>();
762 intExtPortMapList.add(intExtPortMap);
763 Ports ports = new PortsBuilder().withKey(new PortsKey(interfaceName)).setPortName(interfaceName)
764 .setInternalToExternalPortMap(intExtPortMapList).build();
765 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, portsId, ports);
769 void removeOperationalDS(String routerId, String interfaceName, String internalIp) {
770 LOG.info("removeOperationalDS : Remove operational DS for floating ip config: {}", internalIp);
771 InstanceIdentifier<InternalToExternalPortMap> intExtPortMapId = NatUtil.getIntExtPortMapIdentifier(routerId,
772 interfaceName, internalIp);
773 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, intExtPortMapId);
776 private FlowEntity buildPreDNATDeleteFlowEntity(BigInteger dpId, String externalIp, long routerId) {
778 LOG.info("buildPreDNATDeleteFlowEntity : Bulding Delete DNAT Flow entity for ip {} ", externalIp);
780 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PDNAT_TABLE, routerId, externalIp);
782 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PDNAT_TABLE, flowRef,
783 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
784 NwConstants.COOKIE_DNAT_TABLE, null, null);
791 private FlowEntity buildDNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId) {
793 LOG.info("buildDNATDeleteFlowEntity : Bulding Delete DNAT Flow entity for ip {} ", internalIp);
795 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.DNAT_TABLE, routerId, internalIp);
797 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DNAT_TABLE, flowRef,
798 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
799 NwConstants.COOKIE_DNAT_TABLE, null, null);
805 private FlowEntity buildPreSNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId) {
807 LOG.info("buildPreSNATDeleteFlowEntity : Building Delete PSNAT Flow entity for ip {} ", internalIp);
809 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PSNAT_TABLE, routerId, internalIp);
811 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
812 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
813 NwConstants.COOKIE_DNAT_TABLE, null, null);
817 private FlowEntity buildSNATDeleteFlowEntity(BigInteger dpId, String externalIp, long routerId) {
819 LOG.info("buildSNATDeleteFlowEntity : Building Delete SNAT Flow entity for ip {} ", externalIp);
821 String flowRef = NatUtil.getFlowRef(dpId, NwConstants.SNAT_TABLE, routerId, externalIp);
823 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.SNAT_TABLE, flowRef,
824 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
825 NwConstants.COOKIE_DNAT_TABLE, null, null);
830 private void addOrDelDefaultFibRouteForDnat(BigInteger dpnId, String routerName, long routerId,
831 @Nullable TypedReadWriteTransaction<Configuration> confTx, boolean create)
832 throws ExecutionException, InterruptedException {
833 if (confTx == null) {
834 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
835 newTx -> addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, newTx, create)), LOG,
836 "Error handling default FIB route for DNAT");
839 //Check if the router to bgp-vpn association is present
840 long associatedVpnId = NatConstants.INVALID_ID;
841 Uuid associatedVpn = NatUtil.getVpnForRouter(dataBroker, routerName);
842 if (associatedVpn != null) {
843 associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVpn.getValue());
846 if (associatedVpnId != NatConstants.INVALID_ID) {
847 LOG.debug("addOrDelDefaultFibRouteForDnat: Install NAT default route on DPN {} for the router {} with "
848 + "vpn-id {}", dpnId, routerName, associatedVpnId);
849 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, associatedVpnId, routerId, confTx);
851 LOG.debug("addOrDelDefaultFibRouteForDnat: Install NAT default route on DPN {} for the router {} with "
852 + "vpn-id {}", dpnId, routerName, routerId);
853 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, confTx);
856 if (associatedVpnId != NatConstants.INVALID_ID) {
857 LOG.debug("addOrDelDefaultFibRouteForDnat: Remove NAT default route on DPN {} for the router {} "
858 + "with vpn-id {}", dpnId, routerName, associatedVpnId);
859 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, associatedVpnId, routerId, confTx);
861 LOG.debug("addOrDelDefaultFibRouteForDnat: Remove NAT default route on DPN {} for the router {} "
862 + "with vpn-id {}", dpnId, routerName, routerId);
863 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, confTx);