leaf ip-address {\r
type string;\r
}\r
+ leaf ip-address-source {\r
+ description\r
+ "This field indicates whether the IP address here is an External-Fixed-Ip(Owned by Router).\r
+ or Floating-Ip(Used by Ports).";\r
+ type enumeration {\r
+ enum "ExternalFixedIP";\r
+ enum "FloatingIP";\r
+ }\r
+ }\r
uses offlow:instruction-list;\r
}\r
}\r
import javax.inject.Inject;
import javax.inject.Singleton;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
import org.opendaylight.genius.mdsalutil.ActionInfo;
import org.opendaylight.genius.mdsalutil.MDSALUtil;
import org.opendaylight.genius.mdsalutil.MatchInfo;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddressesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddressesKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceKey;
-import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
List<Instruction> instructions = input.getInstruction();
LOG.info("ADD: Adding Custom Fib Entry rd {} prefix {} label {}", vpnRd, ipAddress, input.getServiceId());
makeLocalFibEntry(vpnId, dpnId, ipAddress, instructions);
- updateVpnToDpnAssociation(vpnId, dpnId, ipAddress, vpnName);
+ CreateFibEntryInput.IpAddressSource ipAddressSource = input.getIpAddressSource();
+ updateVpnToDpnAssociation(vpnId, dpnId, ipAddress, ipAddressSource.getIntValue(), vpnName);
LOG.info("ADD: Added Custom Fib Entry rd {} prefix {} label {}", vpnRd, ipAddress, input.getServiceId());
return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
}
+ NwConstants.FLOWID_SEPARATOR + ipAddress;
}
- private synchronized void updateVpnToDpnAssociation(long vpnId, BigInteger dpnId, String ipAddr, String vpnName) {
+ private synchronized void updateVpnToDpnAssociation(long vpnId, BigInteger dpnId, String ipAddr,
+ int ipAddressSourceEnumValue,
+ String vpnName) {
LOG.debug("Updating VPN to DPN list for dpn : {} for VPN: {} with ip: {}",
dpnId, vpnName, ipAddr);
String routeDistinguisher = getVpnRd(dataBroker, vpnName);
String rd = (routeDistinguisher == null) ? vpnName : routeDistinguisher;
+ IpAddresses.IpAddressSource ipAddressSource = (ipAddressSourceEnumValue == 0)
+ ? IpAddresses.IpAddressSource.ExternalFixedIP : IpAddresses.IpAddressSource.FloatingIP;
synchronized (vpnName.intern()) {
InstanceIdentifier<VpnToDpnList> id = getVpnToDpnListIdentifier(rd, dpnId);
Optional<VpnToDpnList> dpnInVpn = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn
.instance.op.data.entry.vpn.to.dpn.list.IpAddresses ipAddress =
- new IpAddressesBuilder().setIpAddress(ipAddr).build();
+ new IpAddressesBuilder().setIpAddress(ipAddr).setIpAddressSource(ipAddressSource).build();
if (dpnInVpn.isPresent()) {
MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, id.child(
if (dpnInVpn.isPresent()) {
List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses> ipAddresses =
- dpnInVpn.get().getIpAddresses();
- org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn
- .instance.op.data.entry.vpn.to.dpn.list.IpAddresses ipAddress =
- new IpAddressesBuilder().setIpAddress(ipAddr).build();
-
- if (ipAddresses != null && ipAddresses.remove(ipAddress)) {
- if (ipAddresses.isEmpty()) {
+ dpnInVpn.get().getIpAddresses();
+ if (ipAddresses != null) {
+ int ipAddressesSize = ipAddresses.size();
+ for (IpAddresses ipAddress : ipAddresses) {
+ if (ipAddress.getIpAddress().equals(ipAddr)) {
+ ipAddressesSize--;
+ }
+ }
+ if (ipAddressesSize == 0) {
List<VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
if (vpnInterfaces == null || vpnInterfaces.isEmpty()) {
//Clean up the dpn
LOG.debug("Cleaning up dpn {} from VPN {}", dpnId, vpnName);
- MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+ try {
+ SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL,
+ id);
+ } catch (TransactionCommitFailedException e) {
+ LOG.error("Failed to delete Dpn {} from Vpn-to-Dpn list for Vpn {}", dpnId, vpnName, e);
+ }
fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd, null);
+ } else {
+ delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id, dpnId, ipAddr, vpnName);
}
} else {
- delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id.child(
- org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
- .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses.class,
- new IpAddressesKey(ipAddr)));
+ delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id, dpnId, ipAddr, vpnName);
}
}
}
return new VpnInstanceOpDataEntryBuilder().setVrfId(rd).setVpnId(vpnId).setVpnInstanceName(vpnName).build();
}
- static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
- InstanceIdentifier<T> path) {
- WriteTransaction tx = broker.newWriteOnlyTransaction();
- tx.delete(datastoreType, path);
- tx.submit();
+ static void delete(DataBroker broker, LogicalDatastoreType datastoreType,
+ InstanceIdentifier<VpnToDpnList> id, BigInteger dpnId, String ipAddr,
+ String vpnName) {
+ try {
+ SingleTransactionDataBroker.syncDelete(broker,datastoreType,id.child(
+ org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op
+ .data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses.class,
+ new IpAddressesKey(ipAddr)));
+ } catch (TransactionCommitFailedException e) {
+ LOG.error("Failed to delete Ip Address {} from Vpn-to-Dpn list for Dpn : {} for Vpn: {}",
+ ipAddr, dpnId, vpnName, e);
+ }
}
static long getVpnId(DataBroker broker, String vpnName) {
LOG.error("NAT Service : Unable to retrieve L3VNI value for Floating IP {} ", externalIp);
return;
}
+ long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
+ if (vpnId == NatConstants.INVALID_ID) {
+ LOG.warn("NAT Service : Invalid Vpn Id is found for Vpn Name {}", vpnName);
+ return;
+ }
FloatingIPListener.updateOperationalDS(dataBroker, routerName, interfaceName, NatConstants.DEFAULT_LABEL_VALUE,
internalIp, externalIp);
- //Inform to FIB
+ //Inform to FIB and BGP
NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, vpnName, rd, externalIp + "/32",
nextHopIp, l3Vni, floatingIpInterface, floatingIpPortMacAddress,
writeTx, RouteOrigin.STATIC, dpnId);
- List<Instruction> instructions = new ArrayList<>();
- List<ActionInfo> actionsInfos = new ArrayList<>();
- List<Instruction> customInstructions = new ArrayList<>();
- customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
- actionsInfos.add(new ActionNxResubmit(NwConstants.PDNAT_TABLE));
- instructions.add(new InstructionApplyActions(actionsInfos).buildInstruction(0));
- /* Install the Flow table INTERNAL_TUNNEL_TABLE (table=36)-> PDNAT_TABLE (table=25) for SNAT to DNAT
- * reverse traffic for Non-FIP VM on DPN1 to FIP VM on DPN2
- */
- makeTunnelTableEntry(dpnId, l3Vni, instructions);
/* Install the flow table L3_FIB_TABLE (table=21)-> PDNAT_TABLE (table=25)
* (SNAT to DNAT reverse traffic: If the DPN has both SNAT and DNAT configured )
*/
instructionsFib.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(1));
CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
- .setSourceDpid(dpnId).setIpAddress(externalIp + "/32").setServiceId(l3Vni)
+ .setSourceDpid(dpnId).setIpAddress(externalIp + "/32")
+ .setServiceId(l3Vni).setIpAddressSource(CreateFibEntryInput.IpAddressSource.FloatingIP)
.setInstruction(instructionsFib).build();
Future<RpcResult<Void>> future1 = fibService.createFibEntry(input);
if (result.isSuccessful()) {
LOG.info("NAT Service : Successfully installed custom FIB routes for Floating "
+ "IP Prefix {} on DPN {}", externalIp, dpnId);
+ List<Instruction> instructions = new ArrayList<>();
+ List<ActionInfo> actionsInfos = new ArrayList<>();
+ List<Instruction> customInstructions = new ArrayList<>();
+ customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
+ actionsInfos.add(new ActionNxResubmit(NwConstants.PDNAT_TABLE));
+ instructions.add(new InstructionApplyActions(actionsInfos).buildInstruction(0));
+ /* Install the Flow table INTERNAL_TUNNEL_TABLE (table=36)-> PDNAT_TABLE (table=25) for SNAT to DNAT
+ * reverse traffic for Non-FIP VM on DPN1 to FIP VM on DPN2
+ */
+ makeTunnelTableEntry(dpnId, l3Vni, instructions);
+
+ /* Install the flow L3_GW_MAC_TABLE (table=19)-> PDNAT_TABLE (table=25)
+ * (DNAT reverse traffic: If the traffic is Initiated from DC-GW to FIP VM (DNAT forward traffic))
+ */
+ NatEvpnUtil.makeL3GwMacTableEntry(dpnId, vpnId, floatingIpPortMacAddress, customInstructions,
+ mdsalManager);
} else {
LOG.error("NAT Service : Error {} in rpc call to create custom Fib entries for Floating "
+ "IP Prefix {} on DPN {}, {}", result.getErrors(), externalIp, dpnId);
}
}
});
- /* Install the flow L3_GW_MAC_TABLE (table=19)-> PDNAT_TABLE (table=25)
- * (DNAT reverse traffic: If the traffic is Initiated from DC-GW to FIP VM (DNAT forward traffic))
- */
- long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
- NatEvpnUtil.makeL3GwMacTableEntry(dpnId, vpnId, floatingIpPortMacAddress, customInstructions, mdsalManager);
//Read the FIP vpn-interface details from Configuration l3vpn:vpn-interfaces model and write into Operational DS
InstanceIdentifier<VpnInterface> vpnIfIdentifier = NatUtil.getVpnInterfaceIdentifier(floatingIpInterface);
LOG.error("NAT Service : Could not retrieve L3VNI value from RD {} in ", rd);
return;
}
+ long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
+ if (vpnId == NatConstants.INVALID_ID) {
+ LOG.warn("NAT Service : Invalid Vpn Id is found for Vpn Name {}", vpnName);
+ return;
+ }
//Remove Prefix from BGP
NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", vpnName, LOG);
- //Remove the flow for INTERNAL_TUNNEL_TABLE (table=36)-> PDNAT_TABLE (table=25)
- removeTunnelTableEntry(dpnId, l3Vni);
-
//Remove custom FIB routes flow for L3_FIB_TABLE (table=21)-> PDNAT_TABLE (table=25)
RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
.setSourceDpid(dpnId).setIpAddress(externalIp + "/32").setServiceId(l3Vni).build();
if (result.isSuccessful()) {
LOG.info("NAT Service : Successfully removed custom FIB routes for Floating "
+ "IP Prefix {} on DPN {}", externalIp, dpnId);
+ /* check if any floating IP information is available in vpn-to-dpn-list for given dpn id.
+ * If exist any floating IP then do not remove
+ * INTERNAL_TUNNEL_TABLE (table=36) -> PDNAT_TABLE (table=25) flow entry.
+ */
+ if (!NatUtil.isFloatingIpPresentForDpn(dataBroker, dpnId, rd, vpnName, externalIp)) {
+ //Remove the flow for INTERNAL_TUNNEL_TABLE (table=36)-> PDNAT_TABLE (table=25)
+ removeTunnelTableEntry(dpnId, l3Vni);
+ }
+ //Remove the flow for L3_GW_MAC_TABLE (table=19)-> PDNAT_TABLE (table=25)
+ NatEvpnUtil.removeL3GwMacTableEntry(dpnId, vpnId, floatingIpPortMacAddress, mdsalManager);
+
} else {
LOG.error("NAT Service : Error {} in rpc call to remove custom Fib entries for Floating "
+ "IP Prefix {} on DPN {}, {}", result.getErrors(), externalIp, dpnId);
}
}
});
-
- long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
- if (vpnId == NatConstants.INVALID_ID) {
- LOG.warn("NAT Service : Invalid Vpn Id is found for Vpn Name {}", vpnName);
- }
- //Remove the flow for L3_GW_MAC_TABLE (table=19)-> PDNAT_TABLE (table=25)
- NatEvpnUtil.removeL3GwMacTableEntry(dpnId, vpnId, floatingIpPortMacAddress, mdsalManager);
-
//Read the FIP vpn-interface details from Operational l3vpn:vpn-interfaces model and delete from Operational DS
InstanceIdentifier<VpnInterface> vpnIfIdentifier = NatUtil.getVpnInterfaceIdentifier(floatingIpInterface);
Optional<VpnInterface> optionalVpnInterface = NatUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
String fibExternalIp = externalIp.contains("/32") ? externalIp : (externalIp + "/32");
CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
.setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
+ .setIpAddressSource(CreateFibEntryInput.IpAddressSource.ExternalFixedIP)
.setInstruction(fibTableCustomInstructions).build();
Future<RpcResult<Void>> future1 = fibService.createFibEntry(input);
return JdkFutureAdapters.listenInPoolThread(future1);
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIdsKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalIpsCounter;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId
+ NwConstants.FLOWID_SEPARATOR + uniqueId;
}
+
+ public static Boolean isFloatingIpPresentForDpn(DataBroker dataBroker, BigInteger dpnId, String rd,
+ String vpnName, String externalIp) {
+ InstanceIdentifier<VpnToDpnList> id = getVpnToDpnListIdentifier(rd, dpnId);
+ Optional<VpnToDpnList> dpnInVpn = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+ if (dpnInVpn.isPresent()) {
+ LOG.debug("vpn-to-dpn-list is not empty for vpnName {}, dpn id {}, rd {} and floatingIp {}",
+ vpnName, dpnId, rd, externalIp);
+ List<IpAddresses> ipAddressList = dpnInVpn.get().getIpAddresses();
+ if (ipAddressList.size() > 0) {
+ for (IpAddresses ipAddress: ipAddressList) {
+ if (!ipAddress.getIpAddress().equals(externalIp)
+ && IpAddresses.IpAddressSource.FloatingIP.equals(ipAddress.getIpAddressSource())) {
+ return Boolean.TRUE;
+ }
+ }
+ } else {
+ LOG.debug("vpn-to-dpn-list does not contain any floating IP for DPN {}", dpnId);
+ return Boolean.FALSE;
+ }
+ }
+ return Boolean.FALSE;
+ }
+
+ private static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
+ return InstanceIdentifier.builder(VpnInstanceOpData.class)
+ .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd))
+ .child(VpnToDpnList.class, new VpnToDpnListKey(dpnId)).build();
+ }
}
CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
.setSourceDpid(dpnId).setInstruction(customInstructions)
.setIpAddress(externalIp + "/32").setServiceId(label)
+ .setIpAddressSource(CreateFibEntryInput.IpAddressSource.FloatingIP)
.setInstruction(customInstructions).build();
//Future<RpcResult<java.lang.Void>> createFibEntry(CreateFibEntryInput input);
Future<RpcResult<Void>> future1 = fibService.createFibEntry(input);
(AsyncFunction<RpcResult<Void>, RpcResult<Void>>) result -> {
//Release label
if (result.isSuccessful()) {
- removeTunnelTableEntry(dpnId, label);
+ /* check if any floating IP information is available in vpn-to-dpn-list for given dpn id. If exist any
+ * floating IP then do not remove INTERNAL_TUNNEL_TABLE (table=36) -> PDNAT_TABLE (table=25) flow entry
+ */
+ Boolean removeTunnelFlow = Boolean.TRUE;
+ if (nvpnManager.getEnforceOpenstackSemanticsConfig()) {
+ if (NatUtil.isFloatingIpPresentForDpn(dataBroker, dpnId, rd, vpnName, externalIp)) {
+ removeTunnelFlow = Boolean.FALSE;
+ }
+ }
+ if (removeTunnelFlow) {
+ removeTunnelTableEntry(dpnId, label);
+ }
removeLFibTableEntry(dpnId, label);
RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
.setVpnName(vpnName).setIpPrefix(externalIp).build();
list ip-addresses {
key ip-address;
leaf ip-address { type string; }
+ leaf ip-address-source {
+ description
+ "This field indicates whether the IP address here is an External-Fixed-Ip(Owned by Router).
+ or Floating-Ip(Used by Ports).";
+ type enumeration {
+ enum "ExternalFixedIP";
+ enum "FloatingIP";
+ }
+ }
}
leaf dpn-state {
description