Reserve POD IP address to avoid allocating duplicated IP addresses
Change-Id: I0fa42d0d17a35184730e797e394502dfceae7525
diff --git a/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/K8sIpamAdminService.java b/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/K8sIpamAdminService.java
index d8752f8..fbca1b3 100644
--- a/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/K8sIpamAdminService.java
+++ b/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/K8sIpamAdminService.java
@@ -33,6 +33,14 @@
IpAddress allocateIp(String networkId);
/**
+ * Reserves an IP address with the given network.
+ *
+ * @param networkId network identifier
+ * @param ipAddress IP address
+ */
+ void reserveIp(String networkId, IpAddress ipAddress);
+
+ /**
* Releases the IP address from the given network.
*
* @param networkId network identifier
diff --git a/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/impl/K8sIpamHandler.java b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/impl/K8sIpamHandler.java
index 5591d2e..4bc6f7c 100644
--- a/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/impl/K8sIpamHandler.java
+++ b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/impl/K8sIpamHandler.java
@@ -15,6 +15,8 @@
*/
package org.onosproject.k8snetworking.impl;
+import io.fabric8.kubernetes.api.model.Pod;
+import org.apache.commons.lang.StringUtils;
import org.onlab.packet.IpAddress;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.LeadershipService;
@@ -25,6 +27,9 @@
import org.onosproject.k8snetworking.api.K8sNetworkEvent;
import org.onosproject.k8snetworking.api.K8sNetworkListener;
import org.onosproject.k8snetworking.api.K8sNetworkService;
+import org.onosproject.k8snetworking.api.K8sPodEvent;
+import org.onosproject.k8snetworking.api.K8sPodListener;
+import org.onosproject.k8snetworking.api.K8sPodService;
import org.onosproject.mastership.MastershipService;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
@@ -33,6 +38,7 @@
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.slf4j.Logger;
+import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -51,6 +57,9 @@
private final Logger log = getLogger(getClass());
+ private static final String IP_ADDRESS = "ipAddress";
+ private static final String NETWORK_ID = "networkId";
+
@Reference(cardinality = ReferenceCardinality.MANDATORY)
protected CoreService coreService;
@@ -67,12 +76,17 @@
protected K8sNetworkService k8sNetworkService;
@Reference(cardinality = ReferenceCardinality.MANDATORY)
+ protected K8sPodService k8sPodService;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY)
protected K8sIpamAdminService k8sIpamAdminService;
private final ExecutorService eventExecutor = newSingleThreadExecutor(
groupedThreads(this.getClass().getSimpleName(), "event-handler"));
private final InternalK8sNetworkListener k8sNetworkListener =
new InternalK8sNetworkListener();
+ private final InternalK8sPodListener k8sPodListener =
+ new InternalK8sPodListener();
private ApplicationId appId;
private NodeId localNodeId;
@@ -83,12 +97,14 @@
localNodeId = clusterService.getLocalNode().id();
leadershipService.runForLeadership(appId.name());
k8sNetworkService.addListener(k8sNetworkListener);
+ k8sPodService.addListener(k8sPodListener);
log.info("Started");
}
@Deactivate
protected void deactivate() {
+ k8sPodService.removeListener(k8sPodListener);
k8sNetworkService.removeListener(k8sNetworkListener);
leadershipService.withdraw(appId.name());
eventExecutor.shutdown();
@@ -133,4 +149,53 @@
k8sIpamAdminService.purgeIpPool(event.subject().networkId());
}
}
+
+ private class InternalK8sPodListener implements K8sPodListener {
+
+ private boolean isRelevantHelper() {
+ return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
+ }
+
+ @Override
+ public void event(K8sPodEvent event) {
+ switch (event.type()) {
+ case K8S_POD_CREATED:
+ eventExecutor.execute(() -> processPodCreation(event.subject()));
+ break;
+ case K8S_POD_REMOVED:
+ default:
+ break;
+ }
+ }
+
+ private void processPodCreation(Pod pod) {
+ if (!isRelevantHelper()) {
+ return;
+ }
+
+ Map<String, String> annots = pod.getMetadata().getAnnotations();
+
+ if (annots == null || annots.isEmpty()) {
+ return;
+ }
+
+ String annotIp = annots.get(IP_ADDRESS);
+ String annotNetwork = annots.get(NETWORK_ID);
+ String podIp = pod.getStatus().getPodIP();
+
+ if (podIp == null && annotIp == null) {
+ return;
+ }
+
+ if (annotNetwork == null) {
+ return;
+ }
+
+ if (!StringUtils.equals(annotIp, podIp)) {
+ return;
+ }
+
+ k8sIpamAdminService.reserveIp(annotNetwork, IpAddress.valueOf(podIp));
+ }
+ }
}
diff --git a/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/impl/K8sIpamManager.java b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/impl/K8sIpamManager.java
index 5501971..7a458c8 100644
--- a/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/impl/K8sIpamManager.java
+++ b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/impl/K8sIpamManager.java
@@ -92,6 +92,18 @@
}
@Override
+ public void reserveIp(String networkId, IpAddress ipAddress) {
+ if (!allocatedIps(networkId).contains(ipAddress)) {
+ String ipamId = networkId + "-" + ipAddress.toString();
+ k8sIpamStore.removeAvailableIp(ipamId);
+ k8sIpamStore.createAllocatedIp(
+ new DefaultK8sIpam(ipamId, ipAddress, networkId));
+
+ log.info("Reserved the IP {}", ipAddress.toString());
+ }
+ }
+
+ @Override
public boolean releaseIp(String networkId, IpAddress ipAddress) {
IpAddress releasedIp = allocatedIps(networkId).stream()
.filter(ip -> ip.equals(ipAddress))
diff --git a/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/util/K8sNetworkingUtil.java b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/util/K8sNetworkingUtil.java
index a263359..a9601d1 100644
--- a/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/util/K8sNetworkingUtil.java
+++ b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/util/K8sNetworkingUtil.java
@@ -168,14 +168,14 @@
*/
public static Set<IpAddress> getSubnetIps(String cidr) {
SubnetUtils utils = new SubnetUtils(cidr);
- utils.setInclusiveHostCount(true);
+ utils.setInclusiveHostCount(false);
SubnetUtils.SubnetInfo info = utils.getInfo();
Set<String> allAddresses =
new HashSet<>(Arrays.asList(info.getAllAddresses()));
if (allAddresses.size() > 2) {
- allAddresses.remove(info.getBroadcastAddress());
- allAddresses.remove(info.getNetworkAddress());
+ allAddresses.remove(info.getLowAddress());
+ allAddresses.remove(info.getHighAddress());
}
return allAddresses.stream()
diff --git a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/util/K8sNetworkUtilTest.java b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/util/K8sNetworkUtilTest.java
index 810c6f0..9a3b34e 100644
--- a/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/util/K8sNetworkUtilTest.java
+++ b/apps/k8s-networking/app/src/test/java/org/onosproject/k8snetworking/util/K8sNetworkUtilTest.java
@@ -35,14 +35,14 @@
public void testGetSubnetIps() {
String bClassCidr = "10.10.0.0/16";
Set<IpAddress> bClassIps = getSubnetIps(bClassCidr);
- assertEquals(((Double) Math.pow(2, 16)).intValue() - 2, bClassIps.size());
+ assertEquals(((Double) Math.pow(2, 16)).intValue() - 4, bClassIps.size());
String cClassCidr = "10.10.10.0/24";
Set<IpAddress> cClassIps = getSubnetIps(cClassCidr);
- assertEquals(((Double) Math.pow(2, 8)).intValue() - 2, cClassIps.size());
+ assertEquals(((Double) Math.pow(2, 8)).intValue() - 4, cClassIps.size());
String dClassCidr = "10.10.10.10/32";
Set<IpAddress> dClassIps = getSubnetIps(dClassCidr);
- assertEquals(1, dClassIps.size());
+ assertEquals(0, dClassIps.size());
}
}