[AETHER-1104] Calculate PiPipeconf fingerprint in a deterministic way
New master after taking over a switch was pushing again the pipeline
and all the flows and groups. This was happening because DefaultPiPipeconf
fingerprint was not calculated in a deterministic way across the cluster.
This patch introduces the following changes:
- Implements toString method in each abstraction representing a pipeline
- Hashes the p4Info file to generate a consistent hash of the pipeline model
- Uses a sorted collection to generate a consistent hash of the extensions
Change-Id: I792283b0a9b821284add36b3aba52843f33527c3
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionModel.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionModel.java
index dec4d1c..6b1af83 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionModel.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionModel.java
@@ -26,6 +26,8 @@
import java.util.Objects;
import java.util.Optional;
+import static com.google.common.base.MoreObjects.toStringHelper;
+
/**
* Implementation of PiActionModel for P4Runtime.
*/
@@ -72,4 +74,12 @@
return Objects.equals(this.id, other.id)
&& Objects.equals(this.params, other.params);
}
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("id", id)
+ .add("params", params.values())
+ .toString();
+ }
}
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionParamModel.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionParamModel.java
index 1c1f0a5..d4a6c4d 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionParamModel.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionParamModel.java
@@ -21,6 +21,8 @@
import java.util.Objects;
+import static com.google.common.base.MoreObjects.toStringHelper;
+
/**
* Implementation of PiActionParamModel for P4Runtime.
*/
@@ -61,4 +63,12 @@
return Objects.equals(this.id, other.id)
&& Objects.equals(this.bitWidth, other.bitWidth);
}
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("id", id)
+ .add("bitWidth", bitWidth)
+ .toString();
+ }
}
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionProfileModel.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionProfileModel.java
index 443d407..5059bce 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionProfileModel.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ActionProfileModel.java
@@ -24,6 +24,8 @@
import java.util.Collection;
import java.util.Objects;
+import static com.google.common.base.MoreObjects.toStringHelper;
+
/**
* Implementation of PiActionProfileModel for P4Runtime.
*/
@@ -90,4 +92,15 @@
&& Objects.equals(this.size, other.size)
&& Objects.equals(this.maxGroupSize, other.maxGroupSize);
}
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("id", id)
+ .add("tables", tables)
+ .add("hasSelector", hasSelector)
+ .add("size", size)
+ .add("maxGroupSize", maxGroupSize)
+ .toString();
+ }
}
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ControlMetadataModel.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ControlMetadataModel.java
index a6e2a43..19a6fa7 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ControlMetadataModel.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4ControlMetadataModel.java
@@ -21,6 +21,8 @@
import java.util.Objects;
+import static com.google.common.base.MoreObjects.toStringHelper;
+
/**
* Implementation of PiPacketMetadataModel for P4Runtime.
*/
@@ -61,4 +63,12 @@
return Objects.equals(this.id, other.id)
&& Objects.equals(this.bitWidth, other.bitWidth);
}
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("id", id)
+ .add("bitWidth", bitWidth)
+ .toString();
+ }
}
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4CounterModel.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4CounterModel.java
index de6e755..01f33ff 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4CounterModel.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4CounterModel.java
@@ -23,6 +23,8 @@
import java.util.Objects;
+import static com.google.common.base.MoreObjects.toStringHelper;
+
/**
* Implementation of PiCounterModel for P4Runtime.
*/
@@ -88,4 +90,15 @@
&& Objects.equals(this.table, other.table)
&& Objects.equals(this.size, other.size);
}
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("id", id)
+ .add("counterType", counterType)
+ .add("unit", unit)
+ .add("table", table)
+ .add("size", size)
+ .toString();
+ }
}
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4InfoParser.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4InfoParser.java
index d5bf2e6..7c1fd1a 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4InfoParser.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4InfoParser.java
@@ -20,6 +20,8 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
+import com.google.common.hash.Hashing;
+import com.google.common.hash.HashingInputStream;
import com.google.protobuf.ExtensionRegistry;
import com.google.protobuf.TextFormat;
import org.onosproject.net.pi.model.PiActionId;
@@ -135,6 +137,19 @@
throw new P4InfoParserException("Unable to parse protobuf " + p4InfoUrl.toString(), e);
}
+ // Generate fingerprint of the pipeline by hashing p4info file
+ final int fingerprint;
+ try {
+ HashingInputStream hin = new HashingInputStream(Hashing.crc32(), p4InfoUrl.openStream());
+ //noinspection StatementWithEmptyBody
+ while (hin.read() != -1) {
+ // Do nothing. Reading all input stream to update hash.
+ }
+ fingerprint = hin.hash().asInt();
+ } catch (IOException e) {
+ throw new P4InfoParserException("Unable to generate fingerprint " + p4InfoUrl.toString(), e);
+ }
+
// Start by parsing and mapping instances to to their integer P4Info IDs.
// Convenient to build the table model at the end.
@@ -243,7 +258,8 @@
meterImmMap,
registerImmMap,
actProfileImmMap,
- ImmutableMap.copyOf(pktOpMap));
+ ImmutableMap.copyOf(pktOpMap),
+ fingerprint);
}
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4MatchFieldModel.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4MatchFieldModel.java
index f3b5ddc..f311acf 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4MatchFieldModel.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4MatchFieldModel.java
@@ -22,6 +22,8 @@
import java.util.Objects;
+import static com.google.common.base.MoreObjects.toStringHelper;
+
/**
* Implementation of PiMatchFieldModel for P4Runtime.
*/
@@ -70,4 +72,13 @@
&& Objects.equals(this.bitWidth, other.bitWidth)
&& Objects.equals(this.matchType, other.matchType);
}
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("id", id)
+ .add("bitWidth", bitWidth)
+ .add("matchType", matchType)
+ .toString();
+ }
}
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4MeterModel.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4MeterModel.java
index 93827cc..a11c8ec 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4MeterModel.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4MeterModel.java
@@ -23,6 +23,8 @@
import java.util.Objects;
+import static com.google.common.base.MoreObjects.toStringHelper;
+
/**
* Implementation of PiMeterModel for P4Runtime.
*/
@@ -87,4 +89,15 @@
&& Objects.equals(this.table, other.table)
&& Objects.equals(this.size, other.size);
}
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("id", id)
+ .add("meterType", meterType)
+ .add("unit", unit)
+ .add("table", table)
+ .add("size", size)
+ .toString();
+ }
}
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4PacketOperationModel.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4PacketOperationModel.java
index e29553f..3421e70 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4PacketOperationModel.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4PacketOperationModel.java
@@ -24,6 +24,8 @@
import java.util.List;
import java.util.Objects;
+import static com.google.common.base.MoreObjects.toStringHelper;
+
/**
* Implementation of PiPacketOperationModel for P4Runtime.
*/
@@ -33,7 +35,7 @@
private final ImmutableList<PiPacketMetadataModel> metadatas;
P4PacketOperationModel(PiPacketOperationType type,
- ImmutableList<PiPacketMetadataModel> metadatas) {
+ ImmutableList<PiPacketMetadataModel> metadatas) {
this.type = type;
this.metadatas = metadatas;
}
@@ -65,4 +67,12 @@
return Objects.equals(this.type, other.type)
&& Objects.equals(this.metadatas, other.metadatas);
}
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("type", type)
+ .add("metadatas", metadatas)
+ .toString();
+ }
}
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4PipelineModel.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4PipelineModel.java
index ce9ec13..28e5372 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4PipelineModel.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4PipelineModel.java
@@ -35,6 +35,8 @@
import java.util.Objects;
import java.util.Optional;
+import static com.google.common.base.MoreObjects.toStringHelper;
+
/**
* Implementation of PiPipelineModel for P4Runtime.
*/
@@ -46,6 +48,7 @@
private final ImmutableMap<PiRegisterId, PiRegisterModel> registers;
private final ImmutableMap<PiActionProfileId, PiActionProfileModel> actionProfiles;
private final ImmutableMap<PiPacketOperationType, PiPacketOperationModel> packetOperations;
+ private final int fingerprint;
P4PipelineModel(
ImmutableMap<PiTableId, PiTableModel> tables,
@@ -53,13 +56,15 @@
ImmutableMap<PiMeterId, PiMeterModel> meters,
ImmutableMap<PiRegisterId, PiRegisterModel> registers,
ImmutableMap<PiActionProfileId, PiActionProfileModel> actionProfiles,
- ImmutableMap<PiPacketOperationType, PiPacketOperationModel> packetOperations) {
+ ImmutableMap<PiPacketOperationType, PiPacketOperationModel> packetOperations,
+ int fingerprint) {
this.tables = tables;
this.counters = counters;
this.meters = meters;
this.registers = registers;
this.actionProfiles = actionProfiles;
this.packetOperations = packetOperations;
+ this.fingerprint = fingerprint;
}
@Override
@@ -120,7 +125,11 @@
@Override
public int hashCode() {
- return Objects.hash(tables, counters, meters, actionProfiles, packetOperations);
+ // NOTE: that the fingerprint is derived by hashing the p4Info file
+ // this because the hashcode is not deterministic across multiple
+ // JVMs instance. This hashcode is also used to derive the fingerprint
+ // of the pipeconf.
+ return fingerprint;
}
@Override
@@ -135,7 +144,22 @@
return Objects.equals(this.tables, other.tables)
&& Objects.equals(this.counters, other.counters)
&& Objects.equals(this.meters, other.meters)
+ && Objects.equals(this.registers, other.registers)
&& Objects.equals(this.actionProfiles, other.actionProfiles)
- && Objects.equals(this.packetOperations, other.packetOperations);
+ && Objects.equals(this.packetOperations, other.packetOperations)
+ && this.fingerprint == other.fingerprint;
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("tables", tables.values())
+ .add("counters", counters.values())
+ .add("meters", meters.values())
+ .add("registers", registers.values())
+ .add("actionProfiles", actionProfiles.values())
+ .add("packetOperations", packetOperations.values())
+ .add("fingerprint", fingerprint)
+ .toString();
}
}
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4RegisterModel.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4RegisterModel.java
index 7e4fcda..44af1e0 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4RegisterModel.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4RegisterModel.java
@@ -21,6 +21,8 @@
import java.util.Objects;
+import static com.google.common.base.MoreObjects.toStringHelper;
+
/**
* Implementation of PiRegisterModel for P4Runtime.
*/
@@ -61,4 +63,12 @@
return Objects.equals(this.id, other.id)
&& Objects.equals(this.size, other.size);
}
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("id", id)
+ .add("size", size)
+ .toString();
+ }
}
\ No newline at end of file
diff --git a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4TableModel.java b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4TableModel.java
index 2eed1bb..be1b71c 100644
--- a/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4TableModel.java
+++ b/protocols/p4runtime/model/src/main/java/org/onosproject/p4runtime/model/P4TableModel.java
@@ -34,6 +34,8 @@
import java.util.Objects;
import java.util.Optional;
+import static com.google.common.base.MoreObjects.toStringHelper;
+
/**
* Implementation of PiTableModel for P4Runtime.
*/
@@ -164,4 +166,21 @@
&& Objects.equals(this.actions, other.actions)
&& Objects.equals(this.constDefaultAction, other.constDefaultAction);
}
+
+ @Override
+ public String toString() {
+ return toStringHelper(this)
+ .add("id", id)
+ .add("tableType", tableType)
+ .add("actionProfile", actionProfile)
+ .add("maxSize", maxSize)
+ .add("counters", counters)
+ .add("meters", meters)
+ .add("supportAging", supportAging)
+ .add("matchFields", matchFields)
+ .add("actions", actions)
+ .add("constDefaultAction", constDefaultAction)
+ .add("isConstTable", isConstTable)
+ .toString();
+ }
}
diff --git a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4PipelineModelTest.java b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4PipelineModelTest.java
index e8b1c70..a6bd76f 100644
--- a/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4PipelineModelTest.java
+++ b/protocols/p4runtime/model/src/test/java/org/onosproject/p4runtime/model/P4PipelineModelTest.java
@@ -340,12 +340,18 @@
.put(PI_PACKET_OPERATION_TYPE_2, P4_PACKET_OPERATION_MODEL_2)
.build();
+ private static final int FINGER_PRINT_1 = 0;
+ private static final int FINGER_PRINT_2 = 1;
+
private static final PiPipelineModel P4_PIPELINE_MODEL_1 =
- new P4PipelineModel(TABLES_1, COUNTERS_1, METERS_1, REGISTERS_1, ACTION_PROFILES_1, PACKET_OPERATIONS_1);
+ new P4PipelineModel(TABLES_1, COUNTERS_1, METERS_1, REGISTERS_1, ACTION_PROFILES_1, PACKET_OPERATIONS_1,
+ FINGER_PRINT_1);
private static final PiPipelineModel SAME_AS_P4_PIPELINE_MODEL_1 =
- new P4PipelineModel(TABLES_1, COUNTERS_1, METERS_1, REGISTERS_1, ACTION_PROFILES_1, PACKET_OPERATIONS_1);
+ new P4PipelineModel(TABLES_1, COUNTERS_1, METERS_1, REGISTERS_1, ACTION_PROFILES_1, PACKET_OPERATIONS_1,
+ FINGER_PRINT_1);
private static final PiPipelineModel P4_PIPELINE_MODEL_2 =
- new P4PipelineModel(TABLES_2, COUNTERS_2, METERS_2, REGISTERS_1, ACTION_PROFILES_2, PACKET_OPERATIONS_2);
+ new P4PipelineModel(TABLES_2, COUNTERS_2, METERS_2, REGISTERS_1, ACTION_PROFILES_2, PACKET_OPERATIONS_2,
+ FINGER_PRINT_2);
/**
* Checks that the P4PipelineModel class is immutable.