@@ -351,7 +351,8 @@ absl::Status SetStringField(google::protobuf::Message* message,
351351 GetFieldDescriptor (*message, fieldname));
352352 RETURN_IF_ERROR (ValidateFieldDescriptorType (field_descriptor,
353353 FieldDescriptor::TYPE_STRING ));
354- message->GetReflection ()->SetString (message, field_descriptor, value);
354+ message->GetReflection ()->SetString (message, field_descriptor,
355+ std::move (value));
355356 return absl::OkStatus ();
356357}
357358
@@ -361,7 +362,8 @@ absl::Status SetBytesField(google::protobuf::Message* message,
361362 GetFieldDescriptor (*message, fieldname));
362363 RETURN_IF_ERROR (ValidateFieldDescriptorType (field_descriptor,
363364 FieldDescriptor::TYPE_BYTES ));
364- message->GetReflection ()->SetString (message, field_descriptor, value);
365+ message->GetReflection ()->SetString (message, field_descriptor,
366+ std::move (value));
365367 return absl::OkStatus ();
366368}
367369
@@ -631,20 +633,32 @@ absl::Status IrTableEntriesToPd(const IrP4Info& ir_p4info,
631633 return absl::OkStatus ();
632634}
633635
636+ // Defined below. See definition for details.
637+ template <typename T>
638+ absl::Status IrPacketIoToPd (const IrP4Info& info, absl::string_view kind,
639+ const T& packet,
640+ google::protobuf::Message* pd_packet,
641+ const TranslationOptions& options,
642+ std::string* movable_payload = nullptr );
643+
634644absl::Status PiPacketInToPd (const IrP4Info& info,
635645 const p4::v1::PacketIn& pi_packet,
636646 google::protobuf::Message* pd_packet,
637647 const TranslationOptions& options) {
638- ASSIGN_OR_RETURN (const auto ir, PiPacketInToIr (info, pi_packet, options));
639- return IrPacketInToPd (info, ir, pd_packet, options);
648+ ASSIGN_OR_RETURN (IrPacketIn ir, PiPacketInToIr (info, pi_packet, options));
649+ // `ir` is a temporary, so its payload can be moved rather than copied.
650+ return IrPacketIoToPd<IrPacketIn>(info, " packet-in" , ir, pd_packet, options,
651+ ir.mutable_payload ());
640652}
641653
642654absl::Status PiPacketOutToPd (const IrP4Info& info,
643655 const p4::v1::PacketOut& pi_packet,
644656 google::protobuf::Message* pd_packet,
645657 const TranslationOptions& options) {
646- ASSIGN_OR_RETURN (const auto ir, PiPacketOutToIr (info, pi_packet, options));
647- return IrPacketOutToPd (info, ir, pd_packet, options);
658+ ASSIGN_OR_RETURN (IrPacketOut ir, PiPacketOutToIr (info, pi_packet, options));
659+ // `ir` is a temporary, so its payload can be moved rather than copied.
660+ return IrPacketIoToPd<IrPacketOut>(info, " packet-out" , ir, pd_packet, options,
661+ ir.mutable_payload ());
648662}
649663
650664absl::Status PiReadRequestToPd (const IrP4Info& info,
@@ -1325,54 +1339,74 @@ absl::Status IrTableEntryToPd(const IrP4Info& ir_p4info, const IrTableEntry& ir,
13251339 return absl::OkStatus ();
13261340}
13271341
1342+ // Generic helper for packet-in and packet-out. If `movable_payload` is
1343+ // non-null, it must point to `packet.payload()` and its contents are moved into
1344+ // `pd_packet` instead of being copied.
1345+ //
1346+ // This function is on the PacketIn/PacketOut hot path, so it avoids copying
1347+ // the metadata definitions and only formats strings on the error path.
13281348template <typename T>
1329- absl::Status IrPacketIoToPd (const IrP4Info& info, const std::string& kind,
1349+ absl::Status IrPacketIoToPd (const IrP4Info& info, absl::string_view kind,
13301350 const T& packet,
13311351 google::protobuf::Message* pd_packet,
1332- const TranslationOptions& options) {
1333- const std::string& packet_description = absl::StrCat (" '" , kind, " ' message" );
1334- const auto & field_descriptor = GetFieldDescriptor (*pd_packet, " payload" );
1335- if (!field_descriptor.ok ()) {
1352+ const TranslationOptions& options,
1353+ std::string* movable_payload) {
1354+ auto packet_description = [kind] {
1355+ return absl::StrCat (" '" , kind, " ' message" );
1356+ };
1357+ const google::protobuf::Map<std::string, IrPacketIoMetadataDefinition>*
1358+ metadata_by_name = nullptr ;
1359+ if (kind == " packet-in" ) {
1360+ metadata_by_name = &info.packet_in_metadata_by_name ();
1361+ } else if (kind == " packet-out" ) {
1362+ metadata_by_name = &info.packet_out_metadata_by_name ();
1363+ } else {
13361364 return absl::InvalidArgumentError (GenerateFormattedError (
1337- packet_description,
1338- absl::StrCat (kNewBullet , field_descriptor. status (). message () )));
1365+ packet_description () ,
1366+ absl::StrCat (kNewBullet , " Invalid PacketIo type. " )));
13391367 }
1340- const auto & validate_status = ValidateFieldDescriptorType (
1341- *field_descriptor, FieldDescriptor::TYPE_BYTES );
1368+
1369+ const google::protobuf::Descriptor* pd_descriptor =
1370+ pd_packet->GetDescriptor ();
1371+ const google::protobuf::Reflection* pd_reflection =
1372+ pd_packet->GetReflection ();
1373+ const FieldDescriptor* payload_field =
1374+ pd_descriptor->FindFieldByName (" payload" );
1375+ if (payload_field == nullptr ) {
1376+ return absl::InvalidArgumentError (GenerateFormattedError (
1377+ packet_description (),
1378+ absl::StrCat (kNewBullet , " Field payload missing in " ,
1379+ pd_packet->GetTypeName ())));
1380+ }
1381+ const auto & validate_status =
1382+ ValidateFieldDescriptorType (payload_field, FieldDescriptor::TYPE_BYTES );
13421383 if (!validate_status.ok ()) {
13431384 return absl::InvalidArgumentError (GenerateFormattedError (
1344- packet_description,
1385+ packet_description () ,
13451386 absl::StrCat (kNewBullet , validate_status.message ())));
13461387 }
1347- pd_packet->GetReflection ()->SetString (pd_packet, *field_descriptor,
1348- packet.payload ());
1349-
1350- google::protobuf::Map<std::string, IrPacketIoMetadataDefinition>
1351- metadata_by_name;
1352- if (kind == " packet-in" ) {
1353- metadata_by_name = info.packet_in_metadata_by_name ();
1354- } else if (kind == " packet-out" ) {
1355- metadata_by_name = info.packet_out_metadata_by_name ();
1388+ if (movable_payload != nullptr ) {
1389+ pd_reflection->SetString (pd_packet, payload_field,
1390+ std::move (*movable_payload));
13561391 } else {
1357- return absl::InvalidArgumentError (GenerateFormattedError (
1358- packet_description,
1359- absl::StrCat (kNewBullet , " Invalid PacketIo type." )));
1392+ pd_reflection->SetString (pd_packet, payload_field, packet.payload ());
13601393 }
13611394
13621395 std::vector<std::string> invalid_reasons;
1396+ // Looked up lazily (once) so that packets without metadata leave the PD
1397+ // `metadata` field unset, as before.
1398+ absl::StatusOr<google::protobuf::Message*> pd_metadata;
1399+ bool pd_metadata_initialized = false ;
13631400 for (const auto & metadata : packet.metadata ()) {
13641401 const std::string& name = metadata.name ();
13651402
1366- const auto & status_or_metadata_definition =
1367- gutil::FindPtrOrStatus (metadata_by_name, name);
1368- if (!status_or_metadata_definition.ok ()) {
1403+ const auto it = metadata_by_name->find (name);
1404+ if (it == metadata_by_name->end ()) {
13691405 invalid_reasons.push_back (absl::StrCat (kNewBullet , " Metadata with name '" ,
13701406 name, " ' not defined." ));
13711407 continue ;
13721408 }
1373-
1374- const pdpi::IrPacketIoMetadataDefinition& metadata_definition =
1375- **status_or_metadata_definition;
1409+ const pdpi::IrPacketIoMetadataDefinition& metadata_definition = it->second ;
13761410
13771411 if (metadata_definition.is_padding ()) {
13781412 invalid_reasons.push_back (absl::StrCat (
@@ -1382,22 +1416,17 @@ absl::Status IrPacketIoToPd(const IrP4Info& info, const std::string& kind,
13821416 continue ;
13831417 }
13841418
1385- const absl::StatusOr<std::string>& raw_value =
1386- IrValueString (metadata.value ());
1387- if (!raw_value.ok ()) {
1388- invalid_reasons.push_back (
1389- GenerateReason (MetadataName (name), raw_value.status ().message ()));
1390- continue ;
1419+ if (!pd_metadata_initialized) {
1420+ pd_metadata = GetMutableMessage (pd_packet, " metadata" );
1421+ pd_metadata_initialized = true ;
13911422 }
1392- const absl::StatusOr<google::protobuf::Message*>& pd_metadata =
1393- GetMutableMessage (pd_packet, " metadata" );
13941423 if (!pd_metadata.ok ()) {
13951424 invalid_reasons.push_back (
13961425 GenerateReason (MetadataName (name), pd_metadata.status ().message ()));
13971426 continue ;
13981427 }
1399- const absl::Status& value_status =
1400- SetStringField (*pd_metadata, name, *raw_value );
1428+ const absl::Status value_status =
1429+ SetStringField (*pd_metadata, name, IrValueString (metadata. value ()) );
14011430 if (!value_status.ok ()) {
14021431 invalid_reasons.push_back (
14031432 GenerateReason (MetadataName (name), value_status.message ()));
@@ -1406,7 +1435,7 @@ absl::Status IrPacketIoToPd(const IrP4Info& info, const std::string& kind,
14061435 }
14071436 if (!invalid_reasons.empty ()) {
14081437 return absl::InvalidArgumentError (GenerateFormattedError (
1409- packet_description, absl::StrJoin (invalid_reasons, " \n " )));
1438+ packet_description () , absl::StrJoin (invalid_reasons, " \n " )));
14101439 }
14111440 return absl::OkStatus ();
14121441}
0 commit comments