Add INT watchlist config
- add "watchSubnets" to the netcfg of INT app
Change-Id: I271d9c27692c8969999ece32f8aa08b4392216e0
(cherry picked from commit 906febe058507758b67f7074bb1139e3c6170b52)
diff --git a/apps/inbandtelemetry/api/src/main/java/org/onosproject/inbandtelemetry/api/IntIntent.java b/apps/inbandtelemetry/api/src/main/java/org/onosproject/inbandtelemetry/api/IntIntent.java
index 8ce9d0f..69d538c 100644
--- a/apps/inbandtelemetry/api/src/main/java/org/onosproject/inbandtelemetry/api/IntIntent.java
+++ b/apps/inbandtelemetry/api/src/main/java/org/onosproject/inbandtelemetry/api/IntIntent.java
@@ -16,6 +16,7 @@
package org.onosproject.inbandtelemetry.api;
import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
import org.onosproject.net.behaviour.inbandtelemetry.IntMetadataType;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.TrafficSelector;
@@ -175,6 +176,27 @@
return new Builder();
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ IntIntent intIntent = (IntIntent) o;
+ return Objects.equal(selector, intIntent.selector) &&
+ Objects.equal(metadataTypes, intIntent.metadataTypes) &&
+ headerType == intIntent.headerType &&
+ Objects.equal(reportTypes, intIntent.reportTypes) &&
+ telemetryMode == intIntent.telemetryMode;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(selector, metadataTypes, headerType, reportTypes, telemetryMode);
+ }
+
/**
* An IntIntent builder.
*/
@@ -246,7 +268,6 @@
* @return an IntIntent
*/
public IntIntent build() {
- checkArgument(!selector.criteria().isEmpty(), "Empty selector cannot match any flow.");
checkNotNull(headerType, "Header type cannot be null.");
checkArgument(!reportTypes.isEmpty(), "Report types cannot be empty.");
checkNotNull(telemetryMode, "Telemetry mode cannot be null.");
diff --git a/apps/inbandtelemetry/impl/src/main/java/org/onosproject/inbandtelemetry/impl/SimpleIntManager.java b/apps/inbandtelemetry/impl/src/main/java/org/onosproject/inbandtelemetry/impl/SimpleIntManager.java
index 25d6a50..ffb6b4f 100644
--- a/apps/inbandtelemetry/impl/src/main/java/org/onosproject/inbandtelemetry/impl/SimpleIntManager.java
+++ b/apps/inbandtelemetry/impl/src/main/java/org/onosproject/inbandtelemetry/impl/SimpleIntManager.java
@@ -44,6 +44,8 @@
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostListener;
import org.onosproject.net.host.HostService;
@@ -591,6 +593,32 @@
.enabled(true)
.build();
setConfig(intDeviceConfig);
+
+ // For each watched subnet, we install two INT rules.
+ // One match on the source, another match on the destination.
+ intentMap.clear();
+ config.watchSubnets().forEach(subnet -> {
+ IntIntent.Builder intIntentBuilder = IntIntent.builder()
+ .withReportType(IntIntent.IntReportType.TRACKED_FLOW)
+ .withReportType(IntIntent.IntReportType.DROPPED_PACKET)
+ .withReportType(IntIntent.IntReportType.CONGESTED_QUEUE)
+ .withTelemetryMode(IntIntent.TelemetryMode.POSTCARD);
+ if (subnet.prefixLength() == 0) {
+ // Special case, match any packet
+ installIntIntent(intIntentBuilder
+ .withSelector(DefaultTrafficSelector.emptySelector())
+ .build());
+ } else {
+ TrafficSelector selector = DefaultTrafficSelector.builder()
+ .matchIPSrc(subnet)
+ .build();
+ installIntIntent(intIntentBuilder.withSelector(selector).build());
+ selector = DefaultTrafficSelector.builder()
+ .matchIPDst(subnet)
+ .build();
+ installIntIntent(intIntentBuilder.withSelector(selector).build());
+ }
+ });
});
break;
// TODO: Support removing INT config.
diff --git a/apps/inbandtelemetry/impl/src/test/java/org/onosproject/inbandtelemetry/impl/SimpleIntManagerTest.java b/apps/inbandtelemetry/impl/src/test/java/org/onosproject/inbandtelemetry/impl/SimpleIntManagerTest.java
index 566ed2b..8519ed5 100644
--- a/apps/inbandtelemetry/impl/src/test/java/org/onosproject/inbandtelemetry/impl/SimpleIntManagerTest.java
+++ b/apps/inbandtelemetry/impl/src/test/java/org/onosproject/inbandtelemetry/impl/SimpleIntManagerTest.java
@@ -27,6 +27,7 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.onlab.junit.TestUtils;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.TpPort;
@@ -35,6 +36,7 @@
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.inbandtelemetry.api.IntIntent;
+import org.onosproject.inbandtelemetry.api.IntIntentId;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultDevice;
@@ -58,6 +60,7 @@
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.host.HostService;
+import org.onosproject.store.service.ConsistentMap;
import org.onosproject.store.service.StorageService;
import org.onosproject.store.service.TestStorageService;
@@ -65,6 +68,7 @@
import java.io.InputStream;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createNiceMock;
@@ -90,12 +94,14 @@
private static final int MIN_FLOW_HOP_LATENCY_CHANGE_NS = 32;
private static final String INT_REPORT_CONFIG_KEY = "report";
private static final DeviceId DEVICE_ID = DeviceId.deviceId("device:leaf1");
+ private static final String WATCHED_SUBNET_1 = "192.168.10.0/24";
+ private static final String WATCHED_SUBNET_2 = "192.168.20.0/24";
private static final TrafficSelector FLOW_SELECTOR1 = DefaultTrafficSelector.builder()
- .matchIPDst(IpPrefix.valueOf("192.168.10.0/24"))
+ .matchIPDst(IpPrefix.valueOf(WATCHED_SUBNET_1))
.matchVlanId(VlanId.vlanId((short) 10))
.build();
private static final TrafficSelector FLOW_SELECTOR2 = DefaultTrafficSelector.builder()
- .matchIPDst(IpPrefix.valueOf("192.168.20.0/24"))
+ .matchIPDst(IpPrefix.valueOf(WATCHED_SUBNET_2))
.matchVlanId(VlanId.vlanId((short) 20))
.build();
private static final Device DEFAULT_DEVICE =
@@ -182,6 +188,49 @@
IntDeviceConfig expectedConfig = createIntDeviceConfig();
IntDeviceConfig actualConfig = manager.getConfig();
assertEquals(expectedConfig, actualConfig);
+
+ // Install watch subnets via netcfg
+ // In the report-config.json, there are 3 subnets we want to watch
+ // For subnet 0.0.0.0/0, the IntManager will create only one IntIntent with an empty selector.
+ Set<IntIntent> expectedIntIntents = Sets.newHashSet();
+ ConsistentMap<IntIntentId, IntIntent> intentMap = TestUtils.getField(manager, "intentMap");
+ IntIntent.Builder baseIntentBuilder = IntIntent.builder()
+ .withReportType(IntIntent.IntReportType.TRACKED_FLOW)
+ .withReportType(IntIntent.IntReportType.DROPPED_PACKET)
+ .withReportType(IntIntent.IntReportType.CONGESTED_QUEUE)
+ .withTelemetryMode(IntIntent.TelemetryMode.POSTCARD);
+
+ // Watch IP Src == subnet 1
+ TrafficSelector expectedSelector = DefaultTrafficSelector.builder()
+ .matchIPSrc(IpPrefix.valueOf(WATCHED_SUBNET_1))
+ .build();
+ expectedIntIntents.add(baseIntentBuilder.withSelector(expectedSelector).build());
+ // Watch IP Dst == subnet 1
+ expectedSelector = DefaultTrafficSelector.builder()
+ .matchIPDst(IpPrefix.valueOf(WATCHED_SUBNET_1))
+ .build();
+ expectedIntIntents.add(baseIntentBuilder.withSelector(expectedSelector).build());
+ // Watch IP Src == subnet 2
+ expectedSelector = DefaultTrafficSelector.builder()
+ .matchIPSrc(IpPrefix.valueOf(WATCHED_SUBNET_2))
+ .build();
+ expectedIntIntents.add(baseIntentBuilder.withSelector(expectedSelector).build());
+ // Watch IP Dst == subnet 2
+ expectedSelector = DefaultTrafficSelector.builder()
+ .matchIPDst(IpPrefix.valueOf(WATCHED_SUBNET_2))
+ .build();
+ expectedIntIntents.add(baseIntentBuilder.withSelector(expectedSelector).build());
+ // Any packets
+ expectedSelector = DefaultTrafficSelector.emptySelector();
+ expectedIntIntents.add(baseIntentBuilder.withSelector(expectedSelector).build());
+
+ // The INT intent installation order can be random, so we need to collect
+ // all expected INT intents and check if actual intent exists.
+ assertEquals(5, intentMap.size());
+ intentMap.entrySet().forEach(entry -> {
+ IntIntent actualIntIntent = entry.getValue().value();
+ assertTrue(expectedIntIntents.contains(actualIntIntent));
+ });
}
@Test
diff --git a/apps/inbandtelemetry/impl/src/test/resources/report-config.json b/apps/inbandtelemetry/impl/src/test/resources/report-config.json
index c0c1ca2..366aeab 100644
--- a/apps/inbandtelemetry/impl/src/test/resources/report-config.json
+++ b/apps/inbandtelemetry/impl/src/test/resources/report-config.json
@@ -1,5 +1,10 @@
{
"collectorIp": "10.0.0.1",
"collectorPort": 32766,
- "minFlowHopLatencyChangeNs": 32
+ "minFlowHopLatencyChangeNs": 32,
+ "watchSubnets": [
+ "0.0.0.0/0",
+ "192.168.10.0/24",
+ "192.168.20.0/24"
+ ]
}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/inbandtelemetry/IntObjective.java b/core/api/src/main/java/org/onosproject/net/behaviour/inbandtelemetry/IntObjective.java
index 4d94e62..41d927f 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/inbandtelemetry/IntObjective.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/inbandtelemetry/IntObjective.java
@@ -23,8 +23,6 @@
import java.util.HashSet;
import java.util.Set;
-import static com.google.common.base.Preconditions.checkArgument;
-
/**
* Represents a device-level objective to collect INT metadata for packets
* identified by a traffic selector.
@@ -129,8 +127,6 @@
* @return an IntObjective
*/
public IntObjective build() {
- checkArgument(!selector.criteria().isEmpty(), "Empty selector cannot match any flow.");
-
return new IntObjective(selector, metadataTypes);
}
}
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/inbandtelemetry/IntReportConfig.java b/core/api/src/main/java/org/onosproject/net/behaviour/inbandtelemetry/IntReportConfig.java
index 9575607..158a992 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/inbandtelemetry/IntReportConfig.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/inbandtelemetry/IntReportConfig.java
@@ -15,14 +15,20 @@
*/
package org.onosproject.net.behaviour.inbandtelemetry;
+import com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.common.annotations.Beta;
+import com.google.common.collect.Sets;
import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.TpPort;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.config.Config;
import org.onosproject.ui.JsonUtils;
+import java.util.Collections;
+import java.util.Set;
+
/**
* Application level configuration of the INT process.
* Config example:
@@ -32,7 +38,11 @@
* "report": {
* "collectorIp": "192.168.0.1",
* "collectorPort": 5500,
- * "minFlowHopLatencyChangeNs": 300
+ * "minFlowHopLatencyChangeNs": 300,
+ * "watchSubnets": [
+ * "192.168.0.0/24",
+ * "10.140.0.0/16"
+ * ]
* }
* }
* }
@@ -46,6 +56,7 @@
private static final String COLLECTOR_NEXT_HOP_MAC = "collectorNextHopMac";
private static final String SINK_IP = "sinkIp";
private static final String SINK_MAC = "sinkMac";
+ private static final String WATCH_SUBNETS = "watchSubnets";
/**
* IP address of the collector.
@@ -146,6 +157,24 @@
}
/**
+ * Gets subnets to be watched.
+ *
+ * @return subnets to be watched
+ */
+ public Set<IpPrefix> watchSubnets() {
+ if (object.hasNonNull(WATCH_SUBNETS) && object.path(WATCH_SUBNETS).isArray()) {
+ Set<IpPrefix> subnets = Sets.newHashSet();
+ ArrayNode subnetArray = (ArrayNode) object.path(WATCH_SUBNETS);
+ subnetArray.forEach(subnetNode -> {
+ subnets.add(IpPrefix.valueOf(subnetNode.asText()));
+ });
+ return subnets;
+ } else {
+ return Collections.EMPTY_SET;
+ }
+ }
+
+ /**
* Sets the collector IP to the config.
*
* @param collectorIp the collector IP
@@ -205,4 +234,14 @@
public IntReportConfig setSinkMac(MacAddress sinkMac) {
return (IntReportConfig) setOrClear(SINK_MAC, sinkMac.toString());
}
+
+ /**
+ * Sets subnets to be watched.
+ *
+ * @param subnets subnets to be watched.
+ * @return the config
+ */
+ public IntReportConfig setWatchSubnets(Set<IpPrefix> subnets) {
+ return (IntReportConfig) setOrClear(WATCH_SUBNETS, subnets);
+ }
}