Repository: p4lang/p4runtime
Pull request #556: Add device_id field to capabilites request
Author: login: verios-google
Created: 2025-04-29T22:27:39Z | Merged: 2025-05-09T17:16:07Z

Pretty self-explanatory. A controller can speak to more than one switch, best to know which switch the request is for.


Diff:
diff --git a/docs/v1/P4Runtime-Spec.adoc b/docs/v1/P4Runtime-Spec.adoc
index 484ff331..0718dfc5 100755
--- a/docs/v1/P4Runtime-Spec.adoc
+++ b/docs/v1/P4Runtime-Spec.adoc
@@ -6030,18 +6030,32 @@ error {
 == `Capabilities` RPC
 
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
-discover the capabilities of the P4Runtime server implementation. At the moment,
-the `CapabilitiesRequest` message is empty and the `CapabilitiesResponse`
-message includes the `p4runtime_api_version` string field and the `experimental`
-field, which has type `Any` Protobuf message cite:[ProtoAny].
-
-The `p4runtime_api_version` field must be set to the full semantic version string cite:[SemVer]
-corresponding to the version of the P4Runtime API implemented by the server, e.g. "1.1.0-rc.1".
-
-The ` experimental` field is intended to allow parties to experiment with features
-before proposing them for standardization. NOTE: This field will be deprecated after
-`p4runtime.proto` is migrated from `proto3` to proto `editions`. Proto `extensions` cite:[ProtoExtension]
-will be introduced as the standard way to support experimental use cases.
+discover the capabilities of the P4Runtime server implementation and the devices
+the server controls.
+
+The `CapabilitiesRequest` message contains a single optional field `device_id`.
+
+`device_id` is an optional filter to limit the capabilities in the response to
+those applicable to the target P4 device. A `NOT_FOUND` error is returned if
+the `device_id` is not recognized by the P4Runtime server. If `device_id` is
+unset (i.e. 0), the response should only include capabilities that are
+server-wide (those which are applicable across all devices). Note that if
+`device_id` is set to a valid id, both server-wide and device-specific
+capabilities will be returned.
+
+The `CapabilitiesResponse` message includes the `p4runtime_api_version` string
+field and the `experimental` field, which has type `Any` Protobuf message cite:[ProtoAny].
+
+The `p4runtime_api_version` field must be set to the full semantic version
+string cite:[SemVer] corresponding to the version of the P4Runtime API implemented by the
+server, e.g. "1.1.0-rc.1". This is a server-wide capability.
+
+The ` experimental` field is intended to allow parties to experiment with
+features before proposing them for standardization. This field may contain
+server-wide and/or device-specific capabilities. NOTE: This field will be
+deprecated after `p4runtime.proto` is migrated from `proto3` to proto
+`editions`. Proto `extensions` cite:[ProtoExtension] will be introduced as the standard way
+to support experimental use cases.
 
 Future versions of P4Runtime may introduce more advanced capability discovery
 features. For example, P4Runtime supports three xref:sec-batch-atomicity[atomicity
diff --git a/go/p4/v1/p4runtime.pb.go b/go/p4/v1/p4runtime.pb.go
index d40c4834..cdb74eb3 100644
--- a/go/p4/v1/p4runtime.pb.go
+++ b/go/p4/v1/p4runtime.pb.go
@@ -4471,6 +4471,11 @@ type CapabilitiesRequest struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
+
+	// Optional: Response should include the device-specific capabilities of the
+	// device identified by `device_id` in addition to server-wide capabilities.
+	// Added in v1.5.0
+	DeviceId uint64 `protobuf:"varint,1,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"`
 }
 
 func (x *CapabilitiesRequest) Reset() {
@@ -4505,6 +4510,13 @@ func (*CapabilitiesRequest) Descriptor() ([]byte, []int) {
 	return file_p4_v1_p4runtime_proto_rawDescGZIP(), []int{53}
 }
 
+func (x *CapabilitiesRequest) GetDeviceId() uint64 {
+	if x != nil {
+		return x.DeviceId
+	}
+	return 0
+}
+
 type CapabilitiesResponse struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -5760,61 +5772,63 @@ var file_p4_v1_p4runtime_proto_rawDesc = []byte{
 	0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c,
 	0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
 	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x64,
-	0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69,
-	0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x85, 0x01,
-	0x0a, 0x14, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65,
-	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x34, 0x72, 0x75, 0x6e, 0x74,
-	0x69, 0x6d, 0x65, 0x5f, 0x61, 0x70, 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x70, 0x34, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65,
-	0x41, 0x70, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0c, 0x65, 0x78,
-	0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x18, 0xe7, 0x07, 0x20, 0x01, 0x28,
-	0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d,
-	0x65, 0x6e, 0x74, 0x61, 0x6c, 0x2a, 0x8a, 0x01, 0x0a, 0x07, 0x53, 0x64, 0x6e, 0x50, 0x6f, 0x72,
-	0x74, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x44, 0x4e, 0x5f, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x55, 0x4e,
-	0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x44, 0x4e, 0x5f, 0x50,
-	0x4f, 0x52, 0x54, 0x5f, 0x4d, 0x49, 0x4e, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x0c, 0x53, 0x44, 0x4e,
-	0x5f, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x4d, 0x41, 0x58, 0x10, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0x01, 0x12, 0x21, 0x0a, 0x14, 0x53, 0x44, 0x4e, 0x5f, 0x50, 0x4f, 0x52, 0x54,
-	0x5f, 0x52, 0x45, 0x43, 0x49, 0x52, 0x43, 0x55, 0x4c, 0x41, 0x54, 0x45, 0x10, 0xfa, 0xff, 0xff,
-	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x12, 0x19, 0x0a, 0x0c, 0x53, 0x44, 0x4e, 0x5f, 0x50,
-	0x4f, 0x52, 0x54, 0x5f, 0x43, 0x50, 0x55, 0x10, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-	0xff, 0x01, 0x32, 0x83, 0x04, 0x0a, 0x09, 0x50, 0x34, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65,
-	0x12, 0x34, 0x0a, 0x05, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x70, 0x34, 0x2e, 0x76,
-	0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14,
-	0x2e, 0x70, 0x34, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x33, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x12,
-	0x2e, 0x70, 0x34, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65,
-	0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x34, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52,
-	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x76, 0x0a, 0x1b, 0x53,
-	0x65, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x69, 0x70, 0x65,
-	0x6c, 0x69, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x29, 0x2e, 0x70, 0x34, 0x2e,
-	0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67,
-	0x50, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x70, 0x34, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65,
-	0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x69, 0x70, 0x65, 0x6c,
-	0x69, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
-	0x65, 0x22, 0x00, 0x12, 0x76, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72,
-	0x64, 0x69, 0x6e, 0x67, 0x50, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x66,
-	0x69, 0x67, 0x12, 0x29, 0x2e, 0x70, 0x34, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x6f,
+	0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x32, 0x0a, 0x13, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69,
+	0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a,
+	0x09, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x08, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x22, 0x85, 0x01, 0x0a, 0x14, 0x43,
+	0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x34, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65,
+	0x5f, 0x61, 0x70, 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x13, 0x70, 0x34, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x41, 0x70, 0x69,
+	0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0c, 0x65, 0x78, 0x70, 0x65, 0x72,
+	0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x18, 0xe7, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14,
+	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
+	0x2e, 0x41, 0x6e, 0x79, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74,
+	0x61, 0x6c, 0x2a, 0x8a, 0x01, 0x0a, 0x07, 0x53, 0x64, 0x6e, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x14,
+	0x0a, 0x10, 0x53, 0x44, 0x4e, 0x5f, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f,
+	0x57, 0x4e, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x44, 0x4e, 0x5f, 0x50, 0x4f, 0x52, 0x54,
+	0x5f, 0x4d, 0x49, 0x4e, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x0c, 0x53, 0x44, 0x4e, 0x5f, 0x50, 0x4f,
+	0x52, 0x54, 0x5f, 0x4d, 0x41, 0x58, 0x10, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0x01, 0x12, 0x21, 0x0a, 0x14, 0x53, 0x44, 0x4e, 0x5f, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x52, 0x45,
+	0x43, 0x49, 0x52, 0x43, 0x55, 0x4c, 0x41, 0x54, 0x45, 0x10, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xff, 0xff, 0x01, 0x12, 0x19, 0x0a, 0x0c, 0x53, 0x44, 0x4e, 0x5f, 0x50, 0x4f, 0x52, 0x54,
+	0x5f, 0x43, 0x50, 0x55, 0x10, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x32,
+	0x83, 0x04, 0x0a, 0x09, 0x50, 0x34, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x34, 0x0a,
+	0x05, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x13, 0x2e, 0x70, 0x34, 0x2e, 0x76, 0x31, 0x2e, 0x57,
+	0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x34,
+	0x2e, 0x76, 0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+	0x65, 0x22, 0x00, 0x12, 0x33, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x12, 0x2e, 0x70, 0x34,
+	0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x13, 0x2e, 0x70, 0x34, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x76, 0x0a, 0x1b, 0x53, 0x65, 0x74, 0x46,
+	0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e,
+	0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x29, 0x2e, 0x70, 0x34, 0x2e, 0x76, 0x31, 0x2e,
+	0x53, 0x65, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x69, 0x70,
+	0x65, 0x6c, 0x69, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x70, 0x34, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x46, 0x6f,
 	0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65,
-	0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e,
-	0x70, 0x34, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64,
-	0x69, 0x6e, 0x67, 0x50, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69,
-	0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0d, 0x53,
-	0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1b, 0x2e, 0x70,
-	0x34, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61,
-	0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x34, 0x2e, 0x76,
+	0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
+	0x12, 0x76, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e,
+	0x67, 0x50, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
+	0x29, 0x2e, 0x70, 0x34, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61,
+	0x72, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x43, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x70, 0x34, 0x2e,
+	0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x67,
+	0x50, 0x69, 0x70, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65,
+	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0d, 0x53, 0x74, 0x72, 0x65,
+	0x61, 0x6d, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1b, 0x2e, 0x70, 0x34, 0x2e, 0x76,
 	0x31, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52,
-	0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x49, 0x0a,
-	0x0c, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x2e,
-	0x70, 0x34, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69,
-	0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x34, 0x2e, 0x76,
-	0x31, 0x2e, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65,
-	0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x29, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68,
-	0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x34, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x34,
-	0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x34, 0x2f, 0x76, 0x31,
-	0xf8, 0x01, 0x01, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x34, 0x2e, 0x76, 0x31, 0x2e, 0x53,
+	0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70,
+	0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x49, 0x0a, 0x0c, 0x43, 0x61,
+	0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x34, 0x2e,
+	0x76, 0x31, 0x2e, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x34, 0x2e, 0x76, 0x31, 0x2e, 0x43,
+	0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
+	0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x29, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
+	0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x34, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x34, 0x72, 0x75, 0x6e,
+	0x74, 0x69, 0x6d, 0x65, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x34, 0x2f, 0x76, 0x31, 0xf8, 0x01, 0x01,
+	0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
diff --git a/proto/p4/v1/p4runtime.proto b/proto/p4/v1/p4runtime.proto
index 502d179f..6a565793 100755
--- a/proto/p4/v1/p4runtime.proto
+++ b/proto/p4/v1/p4runtime.proto
@@ -834,7 +834,12 @@ enum SdnPort {
 }
 
 //------------------------------------------------------------------------------
-message CapabilitiesRequest {}
+message CapabilitiesRequest {
+  // Optional: Response should include the device-specific capabilities of the
+  // device identified by `device_id` in addition to server-wide capabilities.
+  // Added in v1.5.0
+  uint64 device_id = 1;
+}
 
 message CapabilitiesResponse {
   // The full semantic version string (e.g. "1.1.0-rc.1") corresponding to the
diff --git a/py/p4/v1/p4runtime_pb2.py b/py/p4/v1/p4runtime_pb2.py
index 7b4af823..a77cbb4e 100644
--- a/py/p4/v1/p4runtime_pb2.py
+++ b/py/p4/v1/p4runtime_pb2.py
@@ -24,7 +24,7 @@
   syntax='proto3',
   serialized_options=b'Z$github.com/p4lang/p4runtime/go/p4/v1\370\001\001',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x15p4/v1/p4runtime.proto\x12\x05p4.v1\x1a\x19google/protobuf/any.proto\x1a\x17google/rpc/status.proto\x1a\x19p4/config/v1/p4info.proto\x1a\x12p4/v1/p4data.proto\"\x8c\x02\n\x0cWriteRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\x04\x12\x13\n\x07role_id\x18\x02 \x01(\x04\x42\x02\x18\x01\x12\x0c\n\x04role\x18\x06 \x01(\t\x12#\n\x0b\x65lection_id\x18\x03 \x01(\x0b\x32\x0e.p4.v1.Uint128\x12\x1e\n\x07updates\x18\x04 \x03(\x0b\x32\r.p4.v1.Update\x12\x30\n\tatomicity\x18\x05 \x01(\x0e\x32\x1d.p4.v1.WriteRequest.Atomicity\"O\n\tAtomicity\x12\x15\n\x11\x43ONTINUE_ON_ERROR\x10\x00\x12\x15\n\x11ROLLBACK_ON_ERROR\x10\x01\x12\x14\n\x10\x44\x41TAPLANE_ATOMIC\x10\x02\"\x0f\n\rWriteResponse\"O\n\x0bReadRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\x04\x12\x0c\n\x04role\x18\x03 \x01(\t\x12\x1f\n\x08\x65ntities\x18\x02 \x03(\x0b\x32\r.p4.v1.Entity\"/\n\x0cReadResponse\x12\x1f\n\x08\x65ntities\x18\x01 \x03(\x0b\x32\r.p4.v1.Entity\"\x86\x01\n\x06Update\x12 \n\x04type\x18\x01 \x01(\x0e\x32\x12.p4.v1.Update.Type\x12\x1d\n\x06\x65ntity\x18\x02 \x01(\x0b\x32\r.p4.v1.Entity\";\n\x04Type\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\n\n\x06INSERT\x10\x01\x12\n\n\x06MODIFY\x10\x02\x12\n\n\x06\x44\x45LETE\x10\x03\"\x87\x05\n\x06\x45ntity\x12*\n\x0c\x65xtern_entry\x18\x01 \x01(\x0b\x32\x12.p4.v1.ExternEntryH\x00\x12(\n\x0btable_entry\x18\x02 \x01(\x0b\x32\x11.p4.v1.TableEntryH\x00\x12;\n\x15\x61\x63tion_profile_member\x18\x03 \x01(\x0b\x32\x1a.p4.v1.ActionProfileMemberH\x00\x12\x39\n\x14\x61\x63tion_profile_group\x18\x04 \x01(\x0b\x32\x19.p4.v1.ActionProfileGroupH\x00\x12(\n\x0bmeter_entry\x18\x05 \x01(\x0b\x32\x11.p4.v1.MeterEntryH\x00\x12\x35\n\x12\x64irect_meter_entry\x18\x06 \x01(\x0b\x32\x17.p4.v1.DirectMeterEntryH\x00\x12,\n\rcounter_entry\x18\x07 \x01(\x0b\x32\x13.p4.v1.CounterEntryH\x00\x12\x39\n\x14\x64irect_counter_entry\x18\x08 \x01(\x0b\x32\x19.p4.v1.DirectCounterEntryH\x00\x12N\n\x1fpacket_replication_engine_entry\x18\t \x01(\x0b\x32#.p4.v1.PacketReplicationEngineEntryH\x00\x12/\n\x0fvalue_set_entry\x18\n \x01(\x0b\x32\x14.p4.v1.ValueSetEntryH\x00\x12.\n\x0eregister_entry\x18\x0b \x01(\x0b\x32\x14.p4.v1.RegisterEntryH\x00\x12*\n\x0c\x64igest_entry\x18\x0c \x01(\x0b\x32\x12.p4.v1.DigestEntryH\x00\x42\x08\n\x06\x65ntity\"]\n\x0b\x45xternEntry\x12\x16\n\x0e\x65xtern_type_id\x18\x01 \x01(\r\x12\x11\n\textern_id\x18\x02 \x01(\r\x12#\n\x05\x65ntry\x18\x03 \x01(\x0b\x32\x14.google.protobuf.Any\"\xd7\x03\n\nTableEntry\x12\x10\n\x08table_id\x18\x01 \x01(\r\x12 \n\x05match\x18\x02 \x03(\x0b\x32\x11.p4.v1.FieldMatch\x12\"\n\x06\x61\x63tion\x18\x03 \x01(\x0b\x32\x12.p4.v1.TableAction\x12\x10\n\x08priority\x18\x04 \x01(\x05\x12\x1f\n\x13\x63ontroller_metadata\x18\x05 \x01(\x04\x42\x02\x18\x01\x12(\n\x0cmeter_config\x18\x06 \x01(\x0b\x32\x12.p4.v1.MeterConfig\x12(\n\x0c\x63ounter_data\x18\x07 \x01(\x0b\x32\x12.p4.v1.CounterData\x12\x33\n\x12meter_counter_data\x18\x0c \x01(\x0b\x32\x17.p4.v1.MeterCounterData\x12\x19\n\x11is_default_action\x18\x08 \x01(\x08\x12\x17\n\x0fidle_timeout_ns\x18\t \x01(\x03\x12:\n\x13time_since_last_hit\x18\n \x01(\x0b\x32\x1d.p4.v1.TableEntry.IdleTimeout\x12\x10\n\x08metadata\x18\x0b \x01(\x0c\x12\x10\n\x08is_const\x18\r \x01(\x08\x1a!\n\x0bIdleTimeout\x12\x12\n\nelapsed_ns\x18\x01 \x01(\x03\"\xda\x03\n\nFieldMatch\x12\x10\n\x08\x66ield_id\x18\x01 \x01(\r\x12(\n\x05\x65xact\x18\x02 \x01(\x0b\x32\x17.p4.v1.FieldMatch.ExactH\x00\x12,\n\x07ternary\x18\x03 \x01(\x0b\x32\x19.p4.v1.FieldMatch.TernaryH\x00\x12$\n\x03lpm\x18\x04 \x01(\x0b\x32\x15.p4.v1.FieldMatch.LPMH\x00\x12(\n\x05range\x18\x06 \x01(\x0b\x32\x17.p4.v1.FieldMatch.RangeH\x00\x12.\n\x08optional\x18\x07 \x01(\x0b\x32\x1a.p4.v1.FieldMatch.OptionalH\x00\x12%\n\x05other\x18\x64 \x01(\x0b\x32\x14.google.protobuf.AnyH\x00\x1a\x16\n\x05\x45xact\x12\r\n\x05value\x18\x01 \x01(\x0c\x1a&\n\x07Ternary\x12\r\n\x05value\x18\x01 \x01(\x0c\x12\x0c\n\x04mask\x18\x02 \x01(\x0c\x1a(\n\x03LPM\x12\r\n\x05value\x18\x01 \x01(\x0c\x12\x12\n\nprefix_len\x18\x02 \x01(\x05\x1a\"\n\x05Range\x12\x0b\n\x03low\x18\x01 \x01(\x0c\x12\x0c\n\x04high\x18\x02 \x01(\x0c\x1a\x19\n\x08Optional\x12\r\n\x05value\x18\x01 \x01(\x0c\x42\x12\n\x10\x66ield_match_type\"\xc1\x01\n\x0bTableAction\x12\x1f\n\x06\x61\x63tion\x18\x01 \x01(\x0b\x32\r.p4.v1.ActionH\x00\x12\"\n\x18\x61\x63tion_profile_member_id\x18\x02 \x01(\rH\x00\x12!\n\x17\x61\x63tion_profile_group_id\x18\x03 \x01(\rH\x00\x12\x42\n\x19\x61\x63tion_profile_action_set\x18\x04 \x01(\x0b\x32\x1d.p4.v1.ActionProfileActionSetH\x00\x42\x06\n\x04type\"j\n\x06\x41\x63tion\x12\x11\n\taction_id\x18\x01 \x01(\r\x12#\n\x06params\x18\x04 \x03(\x0b\x32\x13.p4.v1.Action.Param\x1a(\n\x05Param\x12\x10\n\x08param_id\x18\x02 \x01(\r\x12\r\n\x05value\x18\x03 \x01(\x0c\"T\n\x16\x41\x63tionProfileActionSet\x12:\n\x16\x61\x63tion_profile_actions\x18\x01 \x03(\x0b\x32\x1a.p4.v1.ActionProfileAction\"}\n\x13\x41\x63tionProfileAction\x12\x1d\n\x06\x61\x63tion\x18\x01 \x01(\x0b\x32\r.p4.v1.Action\x12\x0e\n\x06weight\x18\x02 \x01(\x05\x12\x13\n\x05watch\x18\x03 \x01(\x05\x42\x02\x18\x01H\x00\x12\x14\n\nwatch_port\x18\x04 \x01(\x0cH\x00\x42\x0c\n\nwatch_kind\"b\n\x13\x41\x63tionProfileMember\x12\x19\n\x11\x61\x63tion_profile_id\x18\x01 \x01(\r\x12\x11\n\tmember_id\x18\x02 \x01(\r\x12\x1d\n\x06\x61\x63tion\x18\x03 \x01(\x0b\x32\r.p4.v1.Action\"\xec\x01\n\x12\x41\x63tionProfileGroup\x12\x19\n\x11\x61\x63tion_profile_id\x18\x01 \x01(\r\x12\x10\n\x08group_id\x18\x02 \x01(\r\x12\x31\n\x07members\x18\x03 \x03(\x0b\x32 .p4.v1.ActionProfileGroup.Member\x12\x10\n\x08max_size\x18\x04 \x01(\x05\x1a\x64\n\x06Member\x12\x11\n\tmember_id\x18\x01 \x01(\r\x12\x0e\n\x06weight\x18\x02 \x01(\x05\x12\x13\n\x05watch\x18\x03 \x01(\x05\x42\x02\x18\x01H\x00\x12\x14\n\nwatch_port\x18\x04 \x01(\x0cH\x00\x42\x0c\n\nwatch_kind\"\x16\n\x05Index\x12\r\n\x05index\x18\x01 \x01(\x03\"\x8e\x01\n\nMeterEntry\x12\x10\n\x08meter_id\x18\x01 \x01(\r\x12\x1b\n\x05index\x18\x02 \x01(\x0b\x32\x0c.p4.v1.Index\x12\"\n\x06\x63onfig\x18\x03 \x01(\x0b\x32\x12.p4.v1.MeterConfig\x12-\n\x0c\x63ounter_data\x18\x04 \x01(\x0b\x32\x17.p4.v1.MeterCounterData\"\x8d\x01\n\x10\x44irectMeterEntry\x12&\n\x0btable_entry\x18\x01 \x01(\x0b\x32\x11.p4.v1.TableEntry\x12\"\n\x06\x63onfig\x18\x02 \x01(\x0b\x32\x12.p4.v1.MeterConfig\x12-\n\x0c\x63ounter_data\x18\x03 \x01(\x0b\x32\x17.p4.v1.MeterCounterData\"W\n\x0bMeterConfig\x12\x0b\n\x03\x63ir\x18\x01 \x01(\x03\x12\x0e\n\x06\x63\x62urst\x18\x02 \x01(\x03\x12\x0b\n\x03pir\x18\x03 \x01(\x03\x12\x0e\n\x06pburst\x18\x04 \x01(\x03\x12\x0e\n\x06\x65\x62urst\x18\x05 \x01(\x03\"a\n\x0c\x43ounterEntry\x12\x12\n\ncounter_id\x18\x01 \x01(\r\x12\x1b\n\x05index\x18\x02 \x01(\x0b\x32\x0c.p4.v1.Index\x12 \n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32\x12.p4.v1.CounterData\"^\n\x12\x44irectCounterEntry\x12&\n\x0btable_entry\x18\x01 \x01(\x0b\x32\x11.p4.v1.TableEntry\x12 \n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x12.p4.v1.CounterData\"7\n\x0b\x43ounterData\x12\x12\n\nbyte_count\x18\x01 \x01(\x03\x12\x14\n\x0cpacket_count\x18\x02 \x01(\x03\"z\n\x10MeterCounterData\x12!\n\x05green\x18\x01 \x01(\x0b\x32\x12.p4.v1.CounterData\x12\"\n\x06yellow\x18\x02 \x01(\x0b\x32\x12.p4.v1.CounterData\x12\x1f\n\x03red\x18\x03 \x01(\x0b\x32\x12.p4.v1.CounterData\"\x9c\x01\n\x1cPacketReplicationEngineEntry\x12;\n\x15multicast_group_entry\x18\x01 \x01(\x0b\x32\x1a.p4.v1.MulticastGroupEntryH\x00\x12\x37\n\x13\x63lone_session_entry\x18\x02 \x01(\x0b\x32\x18.p4.v1.CloneSessionEntryH\x00\x42\x06\n\x04type\"/\n\rBackupReplica\x12\x0c\n\x04port\x18\x01 \x01(\x0c\x12\x10\n\x08instance\x18\x02 \x01(\r\"\x82\x01\n\x07Replica\x12\x19\n\x0b\x65gress_port\x18\x01 \x01(\rB\x02\x18\x01H\x00\x12\x0e\n\x04port\x18\x03 \x01(\x0cH\x00\x12\x10\n\x08instance\x18\x02 \x01(\r\x12-\n\x0f\x62\x61\x63kup_replicas\x18\x04 \x03(\x0b\x32\x14.p4.v1.BackupReplicaB\x0b\n\tport_kind\"e\n\x13MulticastGroupEntry\x12\x1a\n\x12multicast_group_id\x18\x01 \x01(\r\x12 \n\x08replicas\x18\x02 \x03(\x0b\x32\x0e.p4.v1.Replica\x12\x10\n\x08metadata\x18\x03 \x01(\x0c\"\x80\x01\n\x11\x43loneSessionEntry\x12\x12\n\nsession_id\x18\x01 \x01(\r\x12 \n\x08replicas\x18\x02 \x03(\x0b\x32\x0e.p4.v1.Replica\x12\x18\n\x10\x63lass_of_service\x18\x03 \x01(\r\x12\x1b\n\x13packet_length_bytes\x18\x04 \x01(\x05\"2\n\x0eValueSetMember\x12 \n\x05match\x18\x01 \x03(\x0b\x32\x11.p4.v1.FieldMatch\"M\n\rValueSetEntry\x12\x14\n\x0cvalue_set_id\x18\x01 \x01(\r\x12&\n\x07members\x18\x02 \x03(\x0b\x32\x15.p4.v1.ValueSetMember\"^\n\rRegisterEntry\x12\x13\n\x0bregister_id\x18\x01 \x01(\r\x12\x1b\n\x05index\x18\x02 \x01(\x0b\x32\x0c.p4.v1.Index\x12\x1b\n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32\r.p4.v1.P4Data\"\x9c\x01\n\x0b\x44igestEntry\x12\x11\n\tdigest_id\x18\x01 \x01(\r\x12)\n\x06\x63onfig\x18\x02 \x01(\x0b\x32\x19.p4.v1.DigestEntry.Config\x1aO\n\x06\x43onfig\x12\x16\n\x0emax_timeout_ns\x18\x01 \x01(\x03\x12\x15\n\rmax_list_size\x18\x02 \x01(\x05\x12\x16\n\x0e\x61\x63k_timeout_ns\x18\x03 \x01(\x03\"\xce\x01\n\x14StreamMessageRequest\x12\x35\n\x0b\x61rbitration\x18\x01 \x01(\x0b\x32\x1e.p4.v1.MasterArbitrationUpdateH\x00\x12\"\n\x06packet\x18\x02 \x01(\x0b\x32\x10.p4.v1.PacketOutH\x00\x12*\n\ndigest_ack\x18\x03 \x01(\x0b\x32\x14.p4.v1.DigestListAckH\x00\x12%\n\x05other\x18\x04 \x01(\x0b\x32\x14.google.protobuf.AnyH\x00\x42\x08\n\x06update\"E\n\tPacketOut\x12\x0f\n\x07payload\x18\x01 \x01(\x0c\x12\'\n\x08metadata\x18\x02 \x03(\x0b\x32\x15.p4.v1.PacketMetadata\"3\n\rDigestListAck\x12\x11\n\tdigest_id\x18\x01 \x01(\r\x12\x0f\n\x07list_id\x18\x02 \x01(\x04\"\xb1\x02\n\x15StreamMessageResponse\x12\x35\n\x0b\x61rbitration\x18\x01 \x01(\x0b\x32\x1e.p4.v1.MasterArbitrationUpdateH\x00\x12!\n\x06packet\x18\x02 \x01(\x0b\x32\x0f.p4.v1.PacketInH\x00\x12#\n\x06\x64igest\x18\x03 \x01(\x0b\x32\x11.p4.v1.DigestListH\x00\x12\x43\n\x19idle_timeout_notification\x18\x04 \x01(\x0b\x32\x1e.p4.v1.IdleTimeoutNotificationH\x00\x12%\n\x05other\x18\x05 \x01(\x0b\x32\x14.google.protobuf.AnyH\x00\x12#\n\x05\x65rror\x18\x06 \x01(\x0b\x32\x12.p4.v1.StreamErrorH\x00\x42\x08\n\x06update\"D\n\x08PacketIn\x12\x0f\n\x07payload\x18\x01 \x01(\x0c\x12\'\n\x08metadata\x18\x02 \x03(\x0b\x32\x15.p4.v1.PacketMetadata\"`\n\nDigestList\x12\x11\n\tdigest_id\x18\x01 \x01(\r\x12\x0f\n\x07list_id\x18\x02 \x01(\x04\x12\x1b\n\x04\x64\x61ta\x18\x03 \x03(\x0b\x32\r.p4.v1.P4Data\x12\x11\n\ttimestamp\x18\x04 \x01(\x03\"4\n\x0ePacketMetadata\x12\x13\n\x0bmetadata_id\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\x0c\"\x90\x01\n\x17MasterArbitrationUpdate\x12\x11\n\tdevice_id\x18\x01 \x01(\x04\x12\x19\n\x04role\x18\x02 \x01(\x0b\x32\x0b.p4.v1.Role\x12#\n\x0b\x65lection_id\x18\x03 \x01(\x0b\x32\x0e.p4.v1.Uint128\x12\"\n\x06status\x18\x04 \x01(\x0b\x32\x12.google.rpc.Status\"J\n\x04Role\x12\x0e\n\x02id\x18\x01 \x01(\x04\x42\x02\x18\x01\x12\x0c\n\x04name\x18\x03 \x01(\t\x12$\n\x06\x63onfig\x18\x02 \x01(\x0b\x32\x14.google.protobuf.Any\"T\n\x17IdleTimeoutNotification\x12&\n\x0btable_entry\x18\x01 \x03(\x0b\x32\x11.p4.v1.TableEntry\x12\x11\n\ttimestamp\x18\x02 \x01(\x03\"\xeb\x01\n\x0bStreamError\x12\x16\n\x0e\x63\x61nonical_code\x18\x01 \x01(\x05\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\r\n\x05space\x18\x03 \x01(\t\x12\x0c\n\x04\x63ode\x18\x04 \x01(\x05\x12+\n\npacket_out\x18\x05 \x01(\x0b\x32\x15.p4.v1.PacketOutErrorH\x00\x12\x34\n\x0f\x64igest_list_ack\x18\x06 \x01(\x0b\x32\x19.p4.v1.DigestListAckErrorH\x00\x12(\n\x05other\x18\x07 \x01(\x0b\x32\x17.p4.v1.StreamOtherErrorH\x00\x42\t\n\x07\x64\x65tails\"6\n\x0ePacketOutError\x12$\n\npacket_out\x18\x01 \x01(\x0b\x32\x10.p4.v1.PacketOut\"C\n\x12\x44igestListAckError\x12-\n\x0f\x64igest_list_ack\x18\x01 \x01(\x0b\x32\x14.p4.v1.DigestListAck\"7\n\x10StreamOtherError\x12#\n\x05other\x18\x01 \x01(\x0b\x32\x14.google.protobuf.Any\"$\n\x07Uint128\x12\x0c\n\x04high\x18\x01 \x01(\x04\x12\x0b\n\x03low\x18\x02 \x01(\x04\"\xeb\x02\n\"SetForwardingPipelineConfigRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\x04\x12\x13\n\x07role_id\x18\x02 \x01(\x04\x42\x02\x18\x01\x12\x0c\n\x04role\x18\x06 \x01(\t\x12#\n\x0b\x65lection_id\x18\x03 \x01(\x0b\x32\x0e.p4.v1.Uint128\x12@\n\x06\x61\x63tion\x18\x04 \x01(\x0e\x32\x30.p4.v1.SetForwardingPipelineConfigRequest.Action\x12/\n\x06\x63onfig\x18\x05 \x01(\x0b\x32\x1f.p4.v1.ForwardingPipelineConfig\"w\n\x06\x41\x63tion\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\n\n\x06VERIFY\x10\x01\x12\x13\n\x0fVERIFY_AND_SAVE\x10\x02\x12\x15\n\x11VERIFY_AND_COMMIT\x10\x03\x12\n\n\x06\x43OMMIT\x10\x04\x12\x18\n\x14RECONCILE_AND_COMMIT\x10\x05\"%\n#SetForwardingPipelineConfigResponse\"\xac\x01\n\x18\x46orwardingPipelineConfig\x12$\n\x06p4info\x18\x01 \x01(\x0b\x32\x14.p4.config.v1.P4Info\x12\x18\n\x10p4_device_config\x18\x02 \x01(\x0c\x12\x36\n\x06\x63ookie\x18\x03 \x01(\x0b\x32&.p4.v1.ForwardingPipelineConfig.Cookie\x1a\x18\n\x06\x43ookie\x12\x0e\n\x06\x63ookie\x18\x01 \x01(\x04\"\xe5\x01\n\"GetForwardingPipelineConfigRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\x04\x12M\n\rresponse_type\x18\x02 \x01(\x0e\x32\x36.p4.v1.GetForwardingPipelineConfigRequest.ResponseType\"]\n\x0cResponseType\x12\x07\n\x03\x41LL\x10\x00\x12\x0f\n\x0b\x43OOKIE_ONLY\x10\x01\x12\x15\n\x11P4INFO_AND_COOKIE\x10\x02\x12\x1c\n\x18\x44\x45VICE_CONFIG_AND_COOKIE\x10\x03\"V\n#GetForwardingPipelineConfigResponse\x12/\n\x06\x63onfig\x18\x01 \x01(\x0b\x32\x1f.p4.v1.ForwardingPipelineConfig\"t\n\x05\x45rror\x12\x16\n\x0e\x63\x61nonical_code\x18\x01 \x01(\x05\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\r\n\x05space\x18\x03 \x01(\t\x12\x0c\n\x04\x63ode\x18\x04 \x01(\x05\x12%\n\x07\x64\x65tails\x18\x05 \x01(\x0b\x32\x14.google.protobuf.Any\"\x15\n\x13\x43\x61pabilitiesRequest\"b\n\x14\x43\x61pabilitiesResponse\x12\x1d\n\x15p4runtime_api_version\x18\x01 \x01(\t\x12+\n\x0c\x65xperimental\x18\xe7\x07 \x01(\x0b\x32\x14.google.protobuf.Any*\x8a\x01\n\x07SdnPort\x12\x14\n\x10SDN_PORT_UNKNOWN\x10\x00\x12\x10\n\x0cSDN_PORT_MIN\x10\x01\x12\x19\n\x0cSDN_PORT_MAX\x10\xff\xfd\xff\xff\xff\xff\xff\xff\xff\x01\x12!\n\x14SDN_PORT_RECIRCULATE\x10\xfa\xff\xff\xff\xff\xff\xff\xff\xff\x01\x12\x19\n\x0cSDN_PORT_CPU\x10\xfd\xff\xff\xff\xff\xff\xff\xff\xff\x01\x32\x83\x04\n\tP4Runtime\x12\x34\n\x05Write\x12\x13.p4.v1.WriteRequest\x1a\x14.p4.v1.WriteResponse\"\x00\x12\x33\n\x04Read\x12\x12.p4.v1.ReadRequest\x1a\x13.p4.v1.ReadResponse\"\x00\x30\x01\x12v\n\x1bSetForwardingPipelineConfig\x12).p4.v1.SetForwardingPipelineConfigRequest\x1a*.p4.v1.SetForwardingPipelineConfigResponse\"\x00\x12v\n\x1bGetForwardingPipelineConfig\x12).p4.v1.GetForwardingPipelineConfigRequest\x1a*.p4.v1.GetForwardingPipelineConfigResponse\"\x00\x12P\n\rStreamChannel\x12\x1b.p4.v1.StreamMessageRequest\x1a\x1c.p4.v1.StreamMessageResponse\"\x00(\x01\x30\x01\x12I\n\x0c\x43\x61pabilities\x12\x1a.p4.v1.CapabilitiesRequest\x1a\x1b.p4.v1.CapabilitiesResponse\"\x00\x42)Z$github.com/p4lang/p4runtime/go/p4/v1\xf8\x01\x01\x62\x06proto3'
+  serialized_pb=b'\n\x15p4/v1/p4runtime.proto\x12\x05p4.v1\x1a\x19google/protobuf/any.proto\x1a\x17google/rpc/status.proto\x1a\x19p4/config/v1/p4info.proto\x1a\x12p4/v1/p4data.proto\"\x8c\x02\n\x0cWriteRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\x04\x12\x13\n\x07role_id\x18\x02 \x01(\x04\x42\x02\x18\x01\x12\x0c\n\x04role\x18\x06 \x01(\t\x12#\n\x0b\x65lection_id\x18\x03 \x01(\x0b\x32\x0e.p4.v1.Uint128\x12\x1e\n\x07updates\x18\x04 \x03(\x0b\x32\r.p4.v1.Update\x12\x30\n\tatomicity\x18\x05 \x01(\x0e\x32\x1d.p4.v1.WriteRequest.Atomicity\"O\n\tAtomicity\x12\x15\n\x11\x43ONTINUE_ON_ERROR\x10\x00\x12\x15\n\x11ROLLBACK_ON_ERROR\x10\x01\x12\x14\n\x10\x44\x41TAPLANE_ATOMIC\x10\x02\"\x0f\n\rWriteResponse\"O\n\x0bReadRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\x04\x12\x0c\n\x04role\x18\x03 \x01(\t\x12\x1f\n\x08\x65ntities\x18\x02 \x03(\x0b\x32\r.p4.v1.Entity\"/\n\x0cReadResponse\x12\x1f\n\x08\x65ntities\x18\x01 \x03(\x0b\x32\r.p4.v1.Entity\"\x86\x01\n\x06Update\x12 \n\x04type\x18\x01 \x01(\x0e\x32\x12.p4.v1.Update.Type\x12\x1d\n\x06\x65ntity\x18\x02 \x01(\x0b\x32\r.p4.v1.Entity\";\n\x04Type\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\n\n\x06INSERT\x10\x01\x12\n\n\x06MODIFY\x10\x02\x12\n\n\x06\x44\x45LETE\x10\x03\"\x87\x05\n\x06\x45ntity\x12*\n\x0c\x65xtern_entry\x18\x01 \x01(\x0b\x32\x12.p4.v1.ExternEntryH\x00\x12(\n\x0btable_entry\x18\x02 \x01(\x0b\x32\x11.p4.v1.TableEntryH\x00\x12;\n\x15\x61\x63tion_profile_member\x18\x03 \x01(\x0b\x32\x1a.p4.v1.ActionProfileMemberH\x00\x12\x39\n\x14\x61\x63tion_profile_group\x18\x04 \x01(\x0b\x32\x19.p4.v1.ActionProfileGroupH\x00\x12(\n\x0bmeter_entry\x18\x05 \x01(\x0b\x32\x11.p4.v1.MeterEntryH\x00\x12\x35\n\x12\x64irect_meter_entry\x18\x06 \x01(\x0b\x32\x17.p4.v1.DirectMeterEntryH\x00\x12,\n\rcounter_entry\x18\x07 \x01(\x0b\x32\x13.p4.v1.CounterEntryH\x00\x12\x39\n\x14\x64irect_counter_entry\x18\x08 \x01(\x0b\x32\x19.p4.v1.DirectCounterEntryH\x00\x12N\n\x1fpacket_replication_engine_entry\x18\t \x01(\x0b\x32#.p4.v1.PacketReplicationEngineEntryH\x00\x12/\n\x0fvalue_set_entry\x18\n \x01(\x0b\x32\x14.p4.v1.ValueSetEntryH\x00\x12.\n\x0eregister_entry\x18\x0b \x01(\x0b\x32\x14.p4.v1.RegisterEntryH\x00\x12*\n\x0c\x64igest_entry\x18\x0c \x01(\x0b\x32\x12.p4.v1.DigestEntryH\x00\x42\x08\n\x06\x65ntity\"]\n\x0b\x45xternEntry\x12\x16\n\x0e\x65xtern_type_id\x18\x01 \x01(\r\x12\x11\n\textern_id\x18\x02 \x01(\r\x12#\n\x05\x65ntry\x18\x03 \x01(\x0b\x32\x14.google.protobuf.Any\"\xd7\x03\n\nTableEntry\x12\x10\n\x08table_id\x18\x01 \x01(\r\x12 \n\x05match\x18\x02 \x03(\x0b\x32\x11.p4.v1.FieldMatch\x12\"\n\x06\x61\x63tion\x18\x03 \x01(\x0b\x32\x12.p4.v1.TableAction\x12\x10\n\x08priority\x18\x04 \x01(\x05\x12\x1f\n\x13\x63ontroller_metadata\x18\x05 \x01(\x04\x42\x02\x18\x01\x12(\n\x0cmeter_config\x18\x06 \x01(\x0b\x32\x12.p4.v1.MeterConfig\x12(\n\x0c\x63ounter_data\x18\x07 \x01(\x0b\x32\x12.p4.v1.CounterData\x12\x33\n\x12meter_counter_data\x18\x0c \x01(\x0b\x32\x17.p4.v1.MeterCounterData\x12\x19\n\x11is_default_action\x18\x08 \x01(\x08\x12\x17\n\x0fidle_timeout_ns\x18\t \x01(\x03\x12:\n\x13time_since_last_hit\x18\n \x01(\x0b\x32\x1d.p4.v1.TableEntry.IdleTimeout\x12\x10\n\x08metadata\x18\x0b \x01(\x0c\x12\x10\n\x08is_const\x18\r \x01(\x08\x1a!\n\x0bIdleTimeout\x12\x12\n\nelapsed_ns\x18\x01 \x01(\x03\"\xda\x03\n\nFieldMatch\x12\x10\n\x08\x66ield_id\x18\x01 \x01(\r\x12(\n\x05\x65xact\x18\x02 \x01(\x0b\x32\x17.p4.v1.FieldMatch.ExactH\x00\x12,\n\x07ternary\x18\x03 \x01(\x0b\x32\x19.p4.v1.FieldMatch.TernaryH\x00\x12$\n\x03lpm\x18\x04 \x01(\x0b\x32\x15.p4.v1.FieldMatch.LPMH\x00\x12(\n\x05range\x18\x06 \x01(\x0b\x32\x17.p4.v1.FieldMatch.RangeH\x00\x12.\n\x08optional\x18\x07 \x01(\x0b\x32\x1a.p4.v1.FieldMatch.OptionalH\x00\x12%\n\x05other\x18\x64 \x01(\x0b\x32\x14.google.protobuf.AnyH\x00\x1a\x16\n\x05\x45xact\x12\r\n\x05value\x18\x01 \x01(\x0c\x1a&\n\x07Ternary\x12\r\n\x05value\x18\x01 \x01(\x0c\x12\x0c\n\x04mask\x18\x02 \x01(\x0c\x1a(\n\x03LPM\x12\r\n\x05value\x18\x01 \x01(\x0c\x12\x12\n\nprefix_len\x18\x02 \x01(\x05\x1a\"\n\x05Range\x12\x0b\n\x03low\x18\x01 \x01(\x0c\x12\x0c\n\x04high\x18\x02 \x01(\x0c\x1a\x19\n\x08Optional\x12\r\n\x05value\x18\x01 \x01(\x0c\x42\x12\n\x10\x66ield_match_type\"\xc1\x01\n\x0bTableAction\x12\x1f\n\x06\x61\x63tion\x18\x01 \x01(\x0b\x32\r.p4.v1.ActionH\x00\x12\"\n\x18\x61\x63tion_profile_member_id\x18\x02 \x01(\rH\x00\x12!\n\x17\x61\x63tion_profile_group_id\x18\x03 \x01(\rH\x00\x12\x42\n\x19\x61\x63tion_profile_action_set\x18\x04 \x01(\x0b\x32\x1d.p4.v1.ActionProfileActionSetH\x00\x42\x06\n\x04type\"j\n\x06\x41\x63tion\x12\x11\n\taction_id\x18\x01 \x01(\r\x12#\n\x06params\x18\x04 \x03(\x0b\x32\x13.p4.v1.Action.Param\x1a(\n\x05Param\x12\x10\n\x08param_id\x18\x02 \x01(\r\x12\r\n\x05value\x18\x03 \x01(\x0c\"T\n\x16\x41\x63tionProfileActionSet\x12:\n\x16\x61\x63tion_profile_actions\x18\x01 \x03(\x0b\x32\x1a.p4.v1.ActionProfileAction\"}\n\x13\x41\x63tionProfileAction\x12\x1d\n\x06\x61\x63tion\x18\x01 \x01(\x0b\x32\r.p4.v1.Action\x12\x0e\n\x06weight\x18\x02 \x01(\x05\x12\x13\n\x05watch\x18\x03 \x01(\x05\x42\x02\x18\x01H\x00\x12\x14\n\nwatch_port\x18\x04 \x01(\x0cH\x00\x42\x0c\n\nwatch_kind\"b\n\x13\x41\x63tionProfileMember\x12\x19\n\x11\x61\x63tion_profile_id\x18\x01 \x01(\r\x12\x11\n\tmember_id\x18\x02 \x01(\r\x12\x1d\n\x06\x61\x63tion\x18\x03 \x01(\x0b\x32\r.p4.v1.Action\"\xec\x01\n\x12\x41\x63tionProfileGroup\x12\x19\n\x11\x61\x63tion_profile_id\x18\x01 \x01(\r\x12\x10\n\x08group_id\x18\x02 \x01(\r\x12\x31\n\x07members\x18\x03 \x03(\x0b\x32 .p4.v1.ActionProfileGroup.Member\x12\x10\n\x08max_size\x18\x04 \x01(\x05\x1a\x64\n\x06Member\x12\x11\n\tmember_id\x18\x01 \x01(\r\x12\x0e\n\x06weight\x18\x02 \x01(\x05\x12\x13\n\x05watch\x18\x03 \x01(\x05\x42\x02\x18\x01H\x00\x12\x14\n\nwatch_port\x18\x04 \x01(\x0cH\x00\x42\x0c\n\nwatch_kind\"\x16\n\x05Index\x12\r\n\x05index\x18\x01 \x01(\x03\"\x8e\x01\n\nMeterEntry\x12\x10\n\x08meter_id\x18\x01 \x01(\r\x12\x1b\n\x05index\x18\x02 \x01(\x0b\x32\x0c.p4.v1.Index\x12\"\n\x06\x63onfig\x18\x03 \x01(\x0b\x32\x12.p4.v1.MeterConfig\x12-\n\x0c\x63ounter_data\x18\x04 \x01(\x0b\x32\x17.p4.v1.MeterCounterData\"\x8d\x01\n\x10\x44irectMeterEntry\x12&\n\x0btable_entry\x18\x01 \x01(\x0b\x32\x11.p4.v1.TableEntry\x12\"\n\x06\x63onfig\x18\x02 \x01(\x0b\x32\x12.p4.v1.MeterConfig\x12-\n\x0c\x63ounter_data\x18\x03 \x01(\x0b\x32\x17.p4.v1.MeterCounterData\"W\n\x0bMeterConfig\x12\x0b\n\x03\x63ir\x18\x01 \x01(\x03\x12\x0e\n\x06\x63\x62urst\x18\x02 \x01(\x03\x12\x0b\n\x03pir\x18\x03 \x01(\x03\x12\x0e\n\x06pburst\x18\x04 \x01(\x03\x12\x0e\n\x06\x65\x62urst\x18\x05 \x01(\x03\"a\n\x0c\x43ounterEntry\x12\x12\n\ncounter_id\x18\x01 \x01(\r\x12\x1b\n\x05index\x18\x02 \x01(\x0b\x32\x0c.p4.v1.Index\x12 \n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32\x12.p4.v1.CounterData\"^\n\x12\x44irectCounterEntry\x12&\n\x0btable_entry\x18\x01 \x01(\x0b\x32\x11.p4.v1.TableEntry\x12 \n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x12.p4.v1.CounterData\"7\n\x0b\x43ounterData\x12\x12\n\nbyte_count\x18\x01 \x01(\x03\x12\x14\n\x0cpacket_count\x18\x02 \x01(\x03\"z\n\x10MeterCounterData\x12!\n\x05green\x18\x01 \x01(\x0b\x32\x12.p4.v1.CounterData\x12\"\n\x06yellow\x18\x02 \x01(\x0b\x32\x12.p4.v1.CounterData\x12\x1f\n\x03red\x18\x03 \x01(\x0b\x32\x12.p4.v1.CounterData\"\x9c\x01\n\x1cPacketReplicationEngineEntry\x12;\n\x15multicast_group_entry\x18\x01 \x01(\x0b\x32\x1a.p4.v1.MulticastGroupEntryH\x00\x12\x37\n\x13\x63lone_session_entry\x18\x02 \x01(\x0b\x32\x18.p4.v1.CloneSessionEntryH\x00\x42\x06\n\x04type\"/\n\rBackupReplica\x12\x0c\n\x04port\x18\x01 \x01(\x0c\x12\x10\n\x08instance\x18\x02 \x01(\r\"\x82\x01\n\x07Replica\x12\x19\n\x0b\x65gress_port\x18\x01 \x01(\rB\x02\x18\x01H\x00\x12\x0e\n\x04port\x18\x03 \x01(\x0cH\x00\x12\x10\n\x08instance\x18\x02 \x01(\r\x12-\n\x0f\x62\x61\x63kup_replicas\x18\x04 \x03(\x0b\x32\x14.p4.v1.BackupReplicaB\x0b\n\tport_kind\"e\n\x13MulticastGroupEntry\x12\x1a\n\x12multicast_group_id\x18\x01 \x01(\r\x12 \n\x08replicas\x18\x02 \x03(\x0b\x32\x0e.p4.v1.Replica\x12\x10\n\x08metadata\x18\x03 \x01(\x0c\"\x80\x01\n\x11\x43loneSessionEntry\x12\x12\n\nsession_id\x18\x01 \x01(\r\x12 \n\x08replicas\x18\x02 \x03(\x0b\x32\x0e.p4.v1.Replica\x12\x18\n\x10\x63lass_of_service\x18\x03 \x01(\r\x12\x1b\n\x13packet_length_bytes\x18\x04 \x01(\x05\"2\n\x0eValueSetMember\x12 \n\x05match\x18\x01 \x03(\x0b\x32\x11.p4.v1.FieldMatch\"M\n\rValueSetEntry\x12\x14\n\x0cvalue_set_id\x18\x01 \x01(\r\x12&\n\x07members\x18\x02 \x03(\x0b\x32\x15.p4.v1.ValueSetMember\"^\n\rRegisterEntry\x12\x13\n\x0bregister_id\x18\x01 \x01(\r\x12\x1b\n\x05index\x18\x02 \x01(\x0b\x32\x0c.p4.v1.Index\x12\x1b\n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32\r.p4.v1.P4Data\"\x9c\x01\n\x0b\x44igestEntry\x12\x11\n\tdigest_id\x18\x01 \x01(\r\x12)\n\x06\x63onfig\x18\x02 \x01(\x0b\x32\x19.p4.v1.DigestEntry.Config\x1aO\n\x06\x43onfig\x12\x16\n\x0emax_timeout_ns\x18\x01 \x01(\x03\x12\x15\n\rmax_list_size\x18\x02 \x01(\x05\x12\x16\n\x0e\x61\x63k_timeout_ns\x18\x03 \x01(\x03\"\xce\x01\n\x14StreamMessageRequest\x12\x35\n\x0b\x61rbitration\x18\x01 \x01(\x0b\x32\x1e.p4.v1.MasterArbitrationUpdateH\x00\x12\"\n\x06packet\x18\x02 \x01(\x0b\x32\x10.p4.v1.PacketOutH\x00\x12*\n\ndigest_ack\x18\x03 \x01(\x0b\x32\x14.p4.v1.DigestListAckH\x00\x12%\n\x05other\x18\x04 \x01(\x0b\x32\x14.google.protobuf.AnyH\x00\x42\x08\n\x06update\"E\n\tPacketOut\x12\x0f\n\x07payload\x18\x01 \x01(\x0c\x12\'\n\x08metadata\x18\x02 \x03(\x0b\x32\x15.p4.v1.PacketMetadata\"3\n\rDigestListAck\x12\x11\n\tdigest_id\x18\x01 \x01(\r\x12\x0f\n\x07list_id\x18\x02 \x01(\x04\"\xb1\x02\n\x15StreamMessageResponse\x12\x35\n\x0b\x61rbitration\x18\x01 \x01(\x0b\x32\x1e.p4.v1.MasterArbitrationUpdateH\x00\x12!\n\x06packet\x18\x02 \x01(\x0b\x32\x0f.p4.v1.PacketInH\x00\x12#\n\x06\x64igest\x18\x03 \x01(\x0b\x32\x11.p4.v1.DigestListH\x00\x12\x43\n\x19idle_timeout_notification\x18\x04 \x01(\x0b\x32\x1e.p4.v1.IdleTimeoutNotificationH\x00\x12%\n\x05other\x18\x05 \x01(\x0b\x32\x14.google.protobuf.AnyH\x00\x12#\n\x05\x65rror\x18\x06 \x01(\x0b\x32\x12.p4.v1.StreamErrorH\x00\x42\x08\n\x06update\"D\n\x08PacketIn\x12\x0f\n\x07payload\x18\x01 \x01(\x0c\x12\'\n\x08metadata\x18\x02 \x03(\x0b\x32\x15.p4.v1.PacketMetadata\"`\n\nDigestList\x12\x11\n\tdigest_id\x18\x01 \x01(\r\x12\x0f\n\x07list_id\x18\x02 \x01(\x04\x12\x1b\n\x04\x64\x61ta\x18\x03 \x03(\x0b\x32\r.p4.v1.P4Data\x12\x11\n\ttimestamp\x18\x04 \x01(\x03\"4\n\x0ePacketMetadata\x12\x13\n\x0bmetadata_id\x18\x01 \x01(\r\x12\r\n\x05value\x18\x02 \x01(\x0c\"\x90\x01\n\x17MasterArbitrationUpdate\x12\x11\n\tdevice_id\x18\x01 \x01(\x04\x12\x19\n\x04role\x18\x02 \x01(\x0b\x32\x0b.p4.v1.Role\x12#\n\x0b\x65lection_id\x18\x03 \x01(\x0b\x32\x0e.p4.v1.Uint128\x12\"\n\x06status\x18\x04 \x01(\x0b\x32\x12.google.rpc.Status\"J\n\x04Role\x12\x0e\n\x02id\x18\x01 \x01(\x04\x42\x02\x18\x01\x12\x0c\n\x04name\x18\x03 \x01(\t\x12$\n\x06\x63onfig\x18\x02 \x01(\x0b\x32\x14.google.protobuf.Any\"T\n\x17IdleTimeoutNotification\x12&\n\x0btable_entry\x18\x01 \x03(\x0b\x32\x11.p4.v1.TableEntry\x12\x11\n\ttimestamp\x18\x02 \x01(\x03\"\xeb\x01\n\x0bStreamError\x12\x16\n\x0e\x63\x61nonical_code\x18\x01 \x01(\x05\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\r\n\x05space\x18\x03 \x01(\t\x12\x0c\n\x04\x63ode\x18\x04 \x01(\x05\x12+\n\npacket_out\x18\x05 \x01(\x0b\x32\x15.p4.v1.PacketOutErrorH\x00\x12\x34\n\x0f\x64igest_list_ack\x18\x06 \x01(\x0b\x32\x19.p4.v1.DigestListAckErrorH\x00\x12(\n\x05other\x18\x07 \x01(\x0b\x32\x17.p4.v1.StreamOtherErrorH\x00\x42\t\n\x07\x64\x65tails\"6\n\x0ePacketOutError\x12$\n\npacket_out\x18\x01 \x01(\x0b\x32\x10.p4.v1.PacketOut\"C\n\x12\x44igestListAckError\x12-\n\x0f\x64igest_list_ack\x18\x01 \x01(\x0b\x32\x14.p4.v1.DigestListAck\"7\n\x10StreamOtherError\x12#\n\x05other\x18\x01 \x01(\x0b\x32\x14.google.protobuf.Any\"$\n\x07Uint128\x12\x0c\n\x04high\x18\x01 \x01(\x04\x12\x0b\n\x03low\x18\x02 \x01(\x04\"\xeb\x02\n\"SetForwardingPipelineConfigRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\x04\x12\x13\n\x07role_id\x18\x02 \x01(\x04\x42\x02\x18\x01\x12\x0c\n\x04role\x18\x06 \x01(\t\x12#\n\x0b\x65lection_id\x18\x03 \x01(\x0b\x32\x0e.p4.v1.Uint128\x12@\n\x06\x61\x63tion\x18\x04 \x01(\x0e\x32\x30.p4.v1.SetForwardingPipelineConfigRequest.Action\x12/\n\x06\x63onfig\x18\x05 \x01(\x0b\x32\x1f.p4.v1.ForwardingPipelineConfig\"w\n\x06\x41\x63tion\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\n\n\x06VERIFY\x10\x01\x12\x13\n\x0fVERIFY_AND_SAVE\x10\x02\x12\x15\n\x11VERIFY_AND_COMMIT\x10\x03\x12\n\n\x06\x43OMMIT\x10\x04\x12\x18\n\x14RECONCILE_AND_COMMIT\x10\x05\"%\n#SetForwardingPipelineConfigResponse\"\xac\x01\n\x18\x46orwardingPipelineConfig\x12$\n\x06p4info\x18\x01 \x01(\x0b\x32\x14.p4.config.v1.P4Info\x12\x18\n\x10p4_device_config\x18\x02 \x01(\x0c\x12\x36\n\x06\x63ookie\x18\x03 \x01(\x0b\x32&.p4.v1.ForwardingPipelineConfig.Cookie\x1a\x18\n\x06\x43ookie\x12\x0e\n\x06\x63ookie\x18\x01 \x01(\x04\"\xe5\x01\n\"GetForwardingPipelineConfigRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\x04\x12M\n\rresponse_type\x18\x02 \x01(\x0e\x32\x36.p4.v1.GetForwardingPipelineConfigRequest.ResponseType\"]\n\x0cResponseType\x12\x07\n\x03\x41LL\x10\x00\x12\x0f\n\x0b\x43OOKIE_ONLY\x10\x01\x12\x15\n\x11P4INFO_AND_COOKIE\x10\x02\x12\x1c\n\x18\x44\x45VICE_CONFIG_AND_COOKIE\x10\x03\"V\n#GetForwardingPipelineConfigResponse\x12/\n\x06\x63onfig\x18\x01 \x01(\x0b\x32\x1f.p4.v1.ForwardingPipelineConfig\"t\n\x05\x45rror\x12\x16\n\x0e\x63\x61nonical_code\x18\x01 \x01(\x05\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\r\n\x05space\x18\x03 \x01(\t\x12\x0c\n\x04\x63ode\x18\x04 \x01(\x05\x12%\n\x07\x64\x65tails\x18\x05 \x01(\x0b\x32\x14.google.protobuf.Any\"(\n\x13\x43\x61pabilitiesRequest\x12\x11\n\tdevice_id\x18\x01 \x01(\x04\"b\n\x14\x43\x61pabilitiesResponse\x12\x1d\n\x15p4runtime_api_version\x18\x01 \x01(\t\x12+\n\x0c\x65xperimental\x18\xe7\x07 \x01(\x0b\x32\x14.google.protobuf.Any*\x8a\x01\n\x07SdnPort\x12\x14\n\x10SDN_PORT_UNKNOWN\x10\x00\x12\x10\n\x0cSDN_PORT_MIN\x10\x01\x12\x19\n\x0cSDN_PORT_MAX\x10\xff\xfd\xff\xff\xff\xff\xff\xff\xff\x01\x12!\n\x14SDN_PORT_RECIRCULATE\x10\xfa\xff\xff\xff\xff\xff\xff\xff\xff\x01\x12\x19\n\x0cSDN_PORT_CPU\x10\xfd\xff\xff\xff\xff\xff\xff\xff\xff\x01\x32\x83\x04\n\tP4Runtime\x12\x34\n\x05Write\x12\x13.p4.v1.WriteRequest\x1a\x14.p4.v1.WriteResponse\"\x00\x12\x33\n\x04Read\x12\x12.p4.v1.ReadRequest\x1a\x13.p4.v1.ReadResponse\"\x00\x30\x01\x12v\n\x1bSetForwardingPipelineConfig\x12).p4.v1.SetForwardingPipelineConfigRequest\x1a*.p4.v1.SetForwardingPipelineConfigResponse\"\x00\x12v\n\x1bGetForwardingPipelineConfig\x12).p4.v1.GetForwardingPipelineConfigRequest\x1a*.p4.v1.GetForwardingPipelineConfigResponse\"\x00\x12P\n\rStreamChannel\x12\x1b.p4.v1.StreamMessageRequest\x1a\x1c.p4.v1.StreamMessageResponse\"\x00(\x01\x30\x01\x12I\n\x0c\x43\x61pabilities\x12\x1a.p4.v1.CapabilitiesRequest\x1a\x1b.p4.v1.CapabilitiesResponse\"\x00\x42)Z$github.com/p4lang/p4runtime/go/p4/v1\xf8\x01\x01\x62\x06proto3'
   ,
   dependencies=[google_dot_protobuf_dot_any__pb2.DESCRIPTOR,google_dot_rpc_dot_status__pb2.DESCRIPTOR,p4_dot_config_dot_v1_dot_p4info__pb2.DESCRIPTOR,p4_dot_v1_dot_p4data__pb2.DESCRIPTOR,])
 
@@ -63,8 +63,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=7749,
-  serialized_end=7887,
+  serialized_start=7768,
+  serialized_end=7906,
 )
 _sym_db.RegisterEnumDescriptor(_SDNPORT)
 
@@ -3179,6 +3179,13 @@
   containing_type=None,
   create_key=_descriptor._internal_create_key,
   fields=[
+    _descriptor.FieldDescriptor(
+      name='device_id', full_name='p4.v1.CapabilitiesRequest.device_id', index=0,
+      number=1, type=4, cpp_type=4, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -3192,7 +3199,7 @@
   oneofs=[
   ],
   serialized_start=7625,
-  serialized_end=7646,
+  serialized_end=7665,
 )
 
 
@@ -3230,8 +3237,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=7648,
-  serialized_end=7746,
+  serialized_start=7667,
+  serialized_end=7765,
 )
 
 _WRITEREQUEST.fields_by_name['election_id'].message_type = _UINT128
@@ -4012,8 +4019,8 @@
   index=0,
   serialized_options=None,
   create_key=_descriptor._internal_create_key,
-  serialized_start=7890,
-  serialized_end=8405,
+  serialized_start=7909,
+  serialized_end=8424,
   methods=[
   _descriptor.MethodDescriptor(
     name='Write',
diff --git a/rust/src/p4.v1.rs b/rust/src/p4.v1.rs
index 419ace10..7112c2d6 100644
--- a/rust/src/p4.v1.rs
+++ b/rust/src/p4.v1.rs
@@ -1340,6 +1340,11 @@ pub struct Error {
 #[allow(clippy::derive_partial_eq_without_eq)]
 #[derive(Clone, Copy, PartialEq, ::prost::Message)]
 pub struct CapabilitiesRequest {
+    /// Optional: Response should include the device-specific capabilities of the
+    /// device identified by `device_id` in addition to server-wide capabilities.
+    /// Added in v1.5.0
+    #[prost(uint64, tag="1")]
+    pub device_id: u64,
 }
 #[allow(clippy::derive_partial_eq_without_eq)]
 #[derive(Clone, PartialEq, ::prost::Message)]


Reviews:
user: login: antoninbas
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-29T23:15:47Z
user: login: jonathan-dilorenzo
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-30T16:00:31Z
user: login: chrispsommers
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-01T18:59:52Z
user: login: verios-google
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-01T19:27:02Z
user: login: chrispsommers
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-01T19:31:04Z
user: login: verios-google
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-01T19:35:55Z
user: login: jonathan-dilorenzo
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-01T20:15:38Z
user: login: jonathan-dilorenzo
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-01T20:19:21Z
user: login: chrispsommers
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-01T20:33:26Z
user: login: jonathan-dilorenzo
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-01T20:41:22Z
user: login: chrispsommers
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-01T20:46:13Z
user: login: verios-google
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T22:01:38Z
user: login: verios-google
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T22:01:48Z
user: login: verios-google
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T22:01:55Z
user: login: verios-google
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-02T22:02:43Z
user: login: jonathan-dilorenzo
body: LGTM!
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T19:05:56Z
user: login: chrispsommers
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-07T18:03:00Z
user: login: jonathan-dilorenzo
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-07T18:08:38Z
user: login: chrispsommers
body: LGTM
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-07T18:15:15Z
user: login: antoninbas
body: LGTM, thanks for making the suggested change

I'd recommend making it explicit that 0 is not a valid device_id in a follow-up change. When I looked at the spec the other day, I couldn't find any mention of this, even though we do have a general statement that the zero value for scalar fields is usually not valid.
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-08T19:59:48Z

Review comments:
diff_hunk: @@ -834,7 +834,10 @@ enum SdnPort {
 }
 
 //------------------------------------------------------------------------------
-message CapabilitiesRequest {}
+message CapabilitiesRequest {
+  // Added in v1.5.0
+  uint64 device_id = 1;
path: proto/p4/v1/p4runtime.proto
user: login: antoninbas
body: Is there a way to have this be optional?
The `p4runtime_api_version` would typically be the same for all devices controlled by a P4Runtime server, so if a client just wants to query that information, now it has to provide a `device_id` for no reason.
The notion of capabilities is (intentionally?) pretty broad, but I expect some would be device-independent, and some may be device-specific. Could `device_id` be defined as an optional filter to limit the capabilities in the response to the ones applicable to that specific device? If no `device_id` is provided, the response should only include capabilities which are applicable across all devices, or should include a mapping from device ID to device-specific capabilities in the `experimental` field.
created_at: 2025-04-29T23:15:47Z
author_association: MEMBER
diff_hunk: @@ -834,7 +834,10 @@ enum SdnPort {
 }
 
 //------------------------------------------------------------------------------
-message CapabilitiesRequest {}
+message CapabilitiesRequest {
+  // Added in v1.5.0
+  uint64 device_id = 1;
path: proto/p4/v1/p4runtime.proto
user: login: jonathan-dilorenzo
body: That seems like a reasonable approach to me. Let's say "If unset (or 0), should return only capabilities common to all devices controlled by the server. Otherwise, should return any capabilities applicable to the given device." or something like that?
created_at: 2025-04-30T16:00:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6032,10 +6032,14 @@ error {
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
 discover the capabilities of the P4Runtime server implementation.
 
-The `CapabilitiesRequest` message contains a single field `device_id`.
-
-The `device_id` uniquely identifies the target P4 device. A `NOT_FOUND` error is
-returned if the `device_id` is not recognized by the P4Runtime server.
+The `CapabilitiesRequest` message contains a single optional field `device_id`.
+
+`device_id` is an optional filter to limit the capabilities in the response to those
+applicable to the target P4 device. A `NOT_FOUND` error is returned if the `device_id`
+is not recognized by the P4Runtime server. If `device_id` is unset (or 0), the response
path: docs/v1/P4Runtime-Spec.adoc
user: login: chrispsommers
body: This implies to me that a real device cannot have an id of 0? Excuse me if this is well-known.
created_at: 2025-05-01T18:59:52Z
author_association: COLLABORATOR
diff_hunk: @@ -6032,10 +6032,14 @@ error {
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
 discover the capabilities of the P4Runtime server implementation.
 
-The `CapabilitiesRequest` message contains a single field `device_id`.
-
-The `device_id` uniquely identifies the target P4 device. A `NOT_FOUND` error is
-returned if the `device_id` is not recognized by the P4Runtime server.
+The `CapabilitiesRequest` message contains a single optional field `device_id`.
+
+`device_id` is an optional filter to limit the capabilities in the response to those
+applicable to the target P4 device. A `NOT_FOUND` error is returned if the `device_id`
+is not recognized by the P4Runtime server. If `device_id` is unset (or 0), the response
path: docs/v1/P4Runtime-Spec.adoc
user: login: verios-google
body: Well darn. That's a good observation. I don't believe there's anything outlawing `device_id = 0`.

This means I would have to add the `optional` keyword to the field

This would make migration to proto `editions` a ever so slightly messier. Not necessarily complicated in anyway just a few more toggles to make sure semantics are identical (or we don't care about exact semantic matching)
created_at: 2025-05-01T19:27:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6032,10 +6032,14 @@ error {
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
 discover the capabilities of the P4Runtime server implementation.
 
-The `CapabilitiesRequest` message contains a single field `device_id`.
-
-The `device_id` uniquely identifies the target P4 device. A `NOT_FOUND` error is
-returned if the `device_id` is not recognized by the P4Runtime server.
+The `CapabilitiesRequest` message contains a single optional field `device_id`.
+
+`device_id` is an optional filter to limit the capabilities in the response to those
+applicable to the target P4 device. A `NOT_FOUND` error is returned if the `device_id`
+is not recognized by the P4Runtime server. If `device_id` is unset (or 0), the response
path: docs/v1/P4Runtime-Spec.adoc
user: login: chrispsommers
body: I don't think that adding `optional` changes the semantics of the message. The reader still cannot tell in proto3 if the field was set to 0 or unset, correct? The way this is sometimes handled is to wrap the field in a xxValue message, e.g. [Uint32Value](https://protobuf.dev/reference/java/api-docs/com/google/protobuf/UInt32Value.html)
created_at: 2025-05-01T19:31:04Z
author_association: COLLABORATOR
diff_hunk: @@ -6032,10 +6032,14 @@ error {
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
 discover the capabilities of the P4Runtime server implementation.
 
-The `CapabilitiesRequest` message contains a single field `device_id`.
-
-The `device_id` uniquely identifies the target P4 device. A `NOT_FOUND` error is
-returned if the `device_id` is not recognized by the P4Runtime server.
+The `CapabilitiesRequest` message contains a single optional field `device_id`.
+
+`device_id` is an optional filter to limit the capabilities in the response to those
+applicable to the target P4 device. A `NOT_FOUND` error is returned if the `device_id`
+is not recognized by the P4Runtime server. If `device_id` is unset (or 0), the response
path: docs/v1/P4Runtime-Spec.adoc
user: login: verios-google
body: IIRC, adding the `optional` keyword to field X introduces the function `has_X()`

Messages have this function by default (which is why wrapping works), but enums, numericals, and strings only gain this function if the optional keyword is used. https://protobuf.dev/programming-guides/field_presence/#presence-in-proto3-apis
created_at: 2025-05-01T19:35:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6032,10 +6032,14 @@ error {
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
 discover the capabilities of the P4Runtime server implementation.
 
-The `CapabilitiesRequest` message contains a single field `device_id`.
-
-The `device_id` uniquely identifies the target P4 device. A `NOT_FOUND` error is
-returned if the `device_id` is not recognized by the P4Runtime server.
+The `CapabilitiesRequest` message contains a single optional field `device_id`.
+
+`device_id` is an optional filter to limit the capabilities in the response to those
+applicable to the target P4 device. A `NOT_FOUND` error is returned if the `device_id`
+is not recognized by the P4Runtime server. If `device_id` is unset (or 0), the response
path: docs/v1/P4Runtime-Spec.adoc
user: login: jonathan-dilorenzo
body: @chrispsommers, not clear if it's well known, but indeed implied by the specification. See https://p4.org/p4-spec/docs/p4runtime-spec-working-draft-html-version.html#_set_unset_scalar_fields. That said, this could perhaps be made clearer for each of the fields where you're not allowed to use 0... But I guess it's nice to not have to mention it every time. 

created_at: 2025-05-01T20:15:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6030,10 +6030,19 @@ error {
 == `Capabilities` RPC
 
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
-discover the capabilities of the P4Runtime server implementation. At the moment,
-the `CapabilitiesRequest` message is empty and the `CapabilitiesResponse`
-message includes the `p4runtime_api_version` string field and the `experimental`
-field, which has type `Any` Protobuf message cite:[ProtoAny].
+discover the capabilities of the P4Runtime server implementation.
path: docs/v1/P4Runtime-Spec.adoc
user: login: jonathan-dilorenzo
body: "... and the devices the server controls." ?
created_at: 2025-05-01T20:16:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6030,10 +6030,19 @@ error {
 == `Capabilities` RPC
 
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
-discover the capabilities of the P4Runtime server implementation. At the moment,
-the `CapabilitiesRequest` message is empty and the `CapabilitiesResponse`
-message includes the `p4runtime_api_version` string field and the `experimental`
-field, which has type `Any` Protobuf message cite:[ProtoAny].
+discover the capabilities of the P4Runtime server implementation.
+
+The `CapabilitiesRequest` message contains a single optional field `device_id`.
+
+`device_id` is an optional filter to limit the capabilities in the response to those
+applicable to the target P4 device. A `NOT_FOUND` error is returned if the `device_id`
+is not recognized by the P4Runtime server. If `device_id` is unset (or 0), the response
path: docs/v1/P4Runtime-Spec.adoc
user: login: jonathan-dilorenzo
body: Unset and 0 are also the same, so maybe say "(i.e. 0)" instead just to be clearer?
created_at: 2025-05-01T20:17:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6030,10 +6030,19 @@ error {
 == `Capabilities` RPC
 
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
-discover the capabilities of the P4Runtime server implementation. At the moment,
-the `CapabilitiesRequest` message is empty and the `CapabilitiesResponse`
-message includes the `p4runtime_api_version` string field and the `experimental`
-field, which has type `Any` Protobuf message cite:[ProtoAny].
+discover the capabilities of the P4Runtime server implementation.
+
+The `CapabilitiesRequest` message contains a single optional field `device_id`.
+
+`device_id` is an optional filter to limit the capabilities in the response to those
+applicable to the target P4 device. A `NOT_FOUND` error is returned if the `device_id`
+is not recognized by the P4Runtime server. If `device_id` is unset (or 0), the response
+should only include capabilities that are server-wide (those which are applicable
+across all devices). Note that if `device_id` is set to a valid id, both server-wide and
+device-specific capabilities will be returned.
+
+The `CapabilitiesResponse` message includes the `p4runtime_api_version` string field
+and the `experimental` field, which has type `Any` Protobuf message cite:[ProtoAny].
 
 The `p4runtime_api_version` field must be set to the full semantic version string cite:[SemVer]
path: docs/v1/P4Runtime-Spec.adoc
user: login: jonathan-dilorenzo
body: Worth specifying that this is server-wide? Or e.g. "On success, this should be returned regardless of device ID."?

I'm not married to this though btw.
created_at: 2025-05-01T20:18:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6032,10 +6032,14 @@ error {
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
 discover the capabilities of the P4Runtime server implementation.
 
-The `CapabilitiesRequest` message contains a single field `device_id`.
-
-The `device_id` uniquely identifies the target P4 device. A `NOT_FOUND` error is
-returned if the `device_id` is not recognized by the P4Runtime server.
+The `CapabilitiesRequest` message contains a single optional field `device_id`.
+
+`device_id` is an optional filter to limit the capabilities in the response to those
+applicable to the target P4 device. A `NOT_FOUND` error is returned if the `device_id`
+is not recognized by the P4Runtime server. If `device_id` is unset (or 0), the response
path: docs/v1/P4Runtime-Spec.adoc
user: login: chrispsommers
body: OK, I see. Somehow I thought `optional` was _ignored_ in proto3. I've been toiling in ignorance for years.

That being said, per [8.1.1. Set / Unset Scalar Fields](https://p4.org/p4-spec/docs/p4runtime-spec-working-draft-html-version.html#_set_unset_scalar_fields):
> In Protobuf version 3 (proto3), the default value of scalar fields is 0 for numeric types such as int32, and the empty string "" for string types (string and bytes). An application, such as the P4Runtime client or server, is unable to distinguish between an unset scalar field and a scalar field set to its default value. Therefore, we usually reserve the default values 0 and "" of scalar fields to mean "unset".

I wonder why we didn't extend this topic and articulate that one should add `optional` to a scalar field to allow the reader to distinguish an unset value from a default/0 value?

It seems like in the past we did some backflips dealing with the limitations of default/unset fields lacking `optional`, and I wonder why we didn't solve it by adding `optional` (perhaps due to backwards-compatibility)?
created_at: 2025-05-01T20:33:26Z
author_association: COLLABORATOR
diff_hunk: @@ -6032,10 +6032,14 @@ error {
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
 discover the capabilities of the P4Runtime server implementation.
 
-The `CapabilitiesRequest` message contains a single field `device_id`.
-
-The `device_id` uniquely identifies the target P4 device. A `NOT_FOUND` error is
-returned if the `device_id` is not recognized by the P4Runtime server.
+The `CapabilitiesRequest` message contains a single optional field `device_id`.
+
+`device_id` is an optional filter to limit the capabilities in the response to those
+applicable to the target P4 device. A `NOT_FOUND` error is returned if the `device_id`
+is not recognized by the P4Runtime server. If `device_id` is unset (or 0), the response
path: docs/v1/P4Runtime-Spec.adoc
user: login: jonathan-dilorenzo
body: So, somehow, I'm recalling that Optional is strongly discouraged (maybe because it's forgotten so often, so you should just not use the default value for scalars anyway) and that's why we avoid using it. However, brief googling suggests that we externally recommend always using it: https://protobuf.dev/programming-guides/proto3/#field-labels

So no idea what's going on there :'(. 

Proto3 also didn't have optional for some time, so that may have been why we didn't use it initially at least. That said, I think disallowing default values to be used to refer to specific objects is generally a good idea, so not sure we suffered much from not doing this ;).
created_at: 2025-05-01T20:41:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6032,10 +6032,14 @@ error {
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
 discover the capabilities of the P4Runtime server implementation.
 
-The `CapabilitiesRequest` message contains a single field `device_id`.
-
-The `device_id` uniquely identifies the target P4 device. A `NOT_FOUND` error is
-returned if the `device_id` is not recognized by the P4Runtime server.
+The `CapabilitiesRequest` message contains a single optional field `device_id`.
+
+`device_id` is an optional filter to limit the capabilities in the response to those
+applicable to the target P4 device. A `NOT_FOUND` error is returned if the `device_id`
+is not recognized by the P4Runtime server. If `device_id` is unset (or 0), the response
path: docs/v1/P4Runtime-Spec.adoc
user: login: chrispsommers
body: >Proto3 also didn't have optional for some time

I didn't get the memo when it was added, ROTFL, which probalby explains my confusion. Thanks!
created_at: 2025-05-01T20:46:12Z
author_association: COLLABORATOR
diff_hunk: @@ -6030,10 +6030,19 @@ error {
 == `Capabilities` RPC
 
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
-discover the capabilities of the P4Runtime server implementation. At the moment,
-the `CapabilitiesRequest` message is empty and the `CapabilitiesResponse`
-message includes the `p4runtime_api_version` string field and the `experimental`
-field, which has type `Any` Protobuf message cite:[ProtoAny].
+discover the capabilities of the P4Runtime server implementation.
+
+The `CapabilitiesRequest` message contains a single optional field `device_id`.
+
+`device_id` is an optional filter to limit the capabilities in the response to those
+applicable to the target P4 device. A `NOT_FOUND` error is returned if the `device_id`
+is not recognized by the P4Runtime server. If `device_id` is unset (or 0), the response
path: docs/v1/P4Runtime-Spec.adoc
user: login: verios-google
body: Done
created_at: 2025-05-02T22:01:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6030,10 +6030,19 @@ error {
 == `Capabilities` RPC
 
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
-discover the capabilities of the P4Runtime server implementation. At the moment,
-the `CapabilitiesRequest` message is empty and the `CapabilitiesResponse`
-message includes the `p4runtime_api_version` string field and the `experimental`
-field, which has type `Any` Protobuf message cite:[ProtoAny].
+discover the capabilities of the P4Runtime server implementation.
+
+The `CapabilitiesRequest` message contains a single optional field `device_id`.
+
+`device_id` is an optional filter to limit the capabilities in the response to those
+applicable to the target P4 device. A `NOT_FOUND` error is returned if the `device_id`
+is not recognized by the P4Runtime server. If `device_id` is unset (or 0), the response
+should only include capabilities that are server-wide (those which are applicable
+across all devices). Note that if `device_id` is set to a valid id, both server-wide and
+device-specific capabilities will be returned.
+
+The `CapabilitiesResponse` message includes the `p4runtime_api_version` string field
+and the `experimental` field, which has type `Any` Protobuf message cite:[ProtoAny].
 
 The `p4runtime_api_version` field must be set to the full semantic version string cite:[SemVer]
path: docs/v1/P4Runtime-Spec.adoc
user: login: verios-google
body: Done
created_at: 2025-05-02T22:01:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6030,10 +6030,19 @@ error {
 == `Capabilities` RPC
 
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
-discover the capabilities of the P4Runtime server implementation. At the moment,
-the `CapabilitiesRequest` message is empty and the `CapabilitiesResponse`
-message includes the `p4runtime_api_version` string field and the `experimental`
-field, which has type `Any` Protobuf message cite:[ProtoAny].
+discover the capabilities of the P4Runtime server implementation.
path: docs/v1/P4Runtime-Spec.adoc
user: login: verios-google
body: Done
created_at: 2025-05-02T22:01:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6032,10 +6032,14 @@ error {
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
 discover the capabilities of the P4Runtime server implementation.
 
-The `CapabilitiesRequest` message contains a single field `device_id`.
-
-The `device_id` uniquely identifies the target P4 device. A `NOT_FOUND` error is
-returned if the `device_id` is not recognized by the P4Runtime server.
+The `CapabilitiesRequest` message contains a single optional field `device_id`.
+
+`device_id` is an optional filter to limit the capabilities in the response to those
+applicable to the target P4 device. A `NOT_FOUND` error is returned if the `device_id`
+is not recognized by the P4Runtime server. If `device_id` is unset (or 0), the response
path: docs/v1/P4Runtime-Spec.adoc
user: login: verios-google
body: I updated the documentation to say "unset (i.e. 0)" to specify that they are one in the same. Good enough?
created_at: 2025-05-02T22:02:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6030,18 +6030,32 @@ error {
 == `Capabilities` RPC
 
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
-discover the capabilities of the P4Runtime server implementation. At the moment,
-the `CapabilitiesRequest` message is empty and the `CapabilitiesResponse`
-message includes the `p4runtime_api_version` string field and the `experimental`
-field, which has type `Any` Protobuf message cite:[ProtoAny].
-
-The `p4runtime_api_version` field must be set to the full semantic version string cite:[SemVer]
-corresponding to the version of the P4Runtime API implemented by the server, e.g. "1.1.0-rc.1".
-
-The ` experimental` field is intended to allow parties to experiment with features
-before proposing them for standardization. NOTE: This field will be deprecated after
-`p4runtime.proto` is migrated from `proto3` to proto `editions`. Proto `extensions` cite:[ProtoExtension]
-will be introduced as the standard way to support experimental use cases.
+discover the capabilities of the P4Runtime server implementation and the devices
+the server controls..
path: docs/v1/P4Runtime-Spec.adoc
user: login: jonathan-dilorenzo
body: nit: remove one period.
created_at: 2025-05-06T18:00:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -6032,10 +6032,14 @@ error {
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
 discover the capabilities of the P4Runtime server implementation.
 
-The `CapabilitiesRequest` message contains a single field `device_id`.
-
-The `device_id` uniquely identifies the target P4 device. A `NOT_FOUND` error is
-returned if the `device_id` is not recognized by the P4Runtime server.
+The `CapabilitiesRequest` message contains a single optional field `device_id`.
+
+`device_id` is an optional filter to limit the capabilities in the response to those
+applicable to the target P4 device. A `NOT_FOUND` error is returned if the `device_id`
+is not recognized by the P4Runtime server. If `device_id` is unset (or 0), the response
path: docs/v1/P4Runtime-Spec.adoc
user: login: chrispsommers
body: So, are we OK with the implication that a concrete `device_id` of zero is unsupported, or at least we can't filter for such a `device_id`? I guess we can accept this limitation since this is experimental and will be deprecated.
created_at: 2025-05-07T18:03:00Z
author_association: COLLABORATOR
diff_hunk: @@ -6032,10 +6032,14 @@ error {
 The `Capabilities` RPC offers a mechanism through which a P4Runtime client can
 discover the capabilities of the P4Runtime server implementation.
 
-The `CapabilitiesRequest` message contains a single field `device_id`.
-
-The `device_id` uniquely identifies the target P4 device. A `NOT_FOUND` error is
-returned if the `device_id` is not recognized by the P4Runtime server.
+The `CapabilitiesRequest` message contains a single optional field `device_id`.
+
+`device_id` is an optional filter to limit the capabilities in the response to those
+applicable to the target P4 device. A `NOT_FOUND` error is returned if the `device_id`
+is not recognized by the P4Runtime server. If `device_id` is unset (or 0), the response
path: docs/v1/P4Runtime-Spec.adoc
user: login: jonathan-dilorenzo
body: Yes, I think we are both OK with that and that it is explicitly unsupported by the P4Runtime spec already. That said, I would also support an extra clarification (in a different PR), maybe in https://p4.org/p4-spec/docs/p4runtime-spec-working-draft-html-version.html#sec-client-arbitration-and-controller-replication stating explicitly that device ID 0 is an invalid argument... Though I also see that it's technically redundant with the rest of the spec...
created_at: 2025-05-07T18:08:38Z
author_association: CONTRIBUTOR

PR comments:
user: login: verios-google
created_at: 2025-05-06T18:21:24Z
body: @chrispsommers and @jonathan-dilorenzo, any other open concerns for the PR, otherwise can I get approval and merger
author_association: CONTRIBUTOR
user: login: jonathan-dilorenzo
created_at: 2025-05-07T17:16:04Z
body: So, if we think there's anything to discuss here, @antoninbas and @chrispsommers, then we could chat in meeting on Friday. O.w. I'd be comfortable with this getting merged as it looks now (or with whatever additional comments you have)?
author_association: CONTRIBUTOR
user: login: chrispsommers
created_at: 2025-05-07T18:15:38Z
body: > So, if we think there's anything to discuss here, @antoninbas and @chrispsommers, then we could chat in meeting on Friday. O.w. I'd be comfortable with this getting merged as it looks now (or with whatever additional comments you have)?

I'm OK with as-is.
author_association: COLLABORATOR
user: login: verios-google
created_at: 2025-05-08T17:45:10Z
body: @antoninbas any other concerns or can we merge this
author_association: CONTRIBUTOR
user: login: verios-google
created_at: 2025-05-08T20:51:05Z
body: Sounds good, I'll take a stab at it when I get the time. @chrispsommers can you merge this PR
author_association: CONTRIBUTOR
user: login: chrispsommers
created_at: 2025-05-09T15:15:30Z
body: > Sounds good, I'll take a stab at it when I get the time. @chrispsommers can you merge this PR

If you're going to add a sentence about device_id 0 isn't valid, how about do that before we merge? It sounds trivial and will avoid yet another PR. We can merge in the meeting today, one way or the other.
author_association: COLLABORATOR