@@ -303,8 +303,184 @@ TEST_F(WarmRestartTest, ReconciliationSucceeds) {
303303
304304 // Reset P4RT server
305305 EXPECT_OK (ResetGrpcServerAndClient (/* is_freeze_mode=*/ true ));
306+ EXPECT_OK (p4rt_service_->GetP4rtServer ().RebuildSwStateAfterWarmboot (
307+ {{" Ethernet0" , " 1" }, {" Ethernet4" , " 2" }},
308+ {{" CONTROLLER_PRIORITY_1" , " 32" }, {" CONTROLLER_PRIORITY_2" , " 33" }},
309+ {{" FRONT_PANEL_1" , " 1" }, {" FRONT_PANEL_2" , " 2" }}, kDeviceId ));
306310 // State Verification
307311 EXPECT_OK (p4rt_service_->GetP4rtServer ().VerifyState ());
312+ // Presence of HOST_STATS|CONFIG entry in STATE DB indicates that P4Info was
313+ // pushed before warm reboot and has been restored during warm bootup.
314+ EXPECT_OK (p4rt_service_->GetHostStatsStateDbTable ().ReadTableEntry (" CONFIG" ));
315+
316+ // Packet I/O ports are added async during reconciliation.
317+ EXPECT_OK (p4rt_service_->GetP4rtServer ().AddPacketIoPort (" Ethernet0" ));
318+ EXPECT_OK (p4rt_service_->GetP4rtServer ().AddPacketIoPort (" Ethernet4" ));
319+ EXPECT_OK (p4rt_service_->GetP4rtServer ().AddPacketIoPort (" SEND_TO_INGRESS" ));
320+
321+ // Verify that the ports are added by AddPacketIoPort during reconciliation.
322+ EXPECT_OK (p4rt_service_->GetFakePacketIoInterface ().SendPacketOut (
323+ " Ethernet0" , " test packet" ));
324+ EXPECT_OK (p4rt_service_->GetFakePacketIoInterface ().SendPacketOut (
325+ " Ethernet4" , " test packet" ));
326+ EXPECT_OK (p4rt_service_->GetFakePacketIoInterface ().SendPacketOut (
327+ " SEND_TO_INGRESS" , " test packet" ));
328+
329+ // Verify that UpdateDeviceId() succeded during reconciliation.
330+ const p4::v1::Uint128 election_id = ElectionId (11 );
331+ grpc::ClientContext primary_stream_context;
332+ std::unique_ptr<P4RuntimeStream> primary_stream;
333+ ASSERT_OK_AND_ASSIGN (
334+ primary_stream,
335+ CreatePrimaryConnection (primary_stream_context, kDeviceId , election_id));
336+ }
337+
338+
339+ TEST_F (WarmRestartTest, ReconciliationSucceedsWithAclEntries) {
340+ // Set forwarding config and save P4Info file
341+ SetForwardingPipelineConfigRequest pipeline_request =
342+ GetBasicForwardingRequest ();
343+ pipeline_request.set_action (
344+ SetForwardingPipelineConfigRequest::RECONCILE_AND_COMMIT);
345+ *pipeline_request.mutable_config ()->mutable_p4info () =
346+ sai::GetP4Info (sai::Instantiation::kTor );
347+ ASSERT_OK (p4rt_session_->SetForwardingPipelineConfig (pipeline_request));
348+ EXPECT_THAT (GetSavedConfig (),
349+ IsOkAndHolds (EqualsProto (pipeline_request.config ())));
350+
351+ ASSERT_OK_AND_ASSIGN (p4::v1::WriteRequest request,
352+ test_lib::PdWriteRequestToPi (
353+ R"pb(
354+ updates {
355+ type: INSERT
356+ table_entry {
357+ acl_pre_ingress_table_entry {
358+ match { is_ip { value: "0x1" } }
359+ priority: 10
360+ action { set_vrf { vrf_id: "vrf-1" } }
361+ }
362+ }
363+ }
364+ )pb" ,
365+ sai::GetIrP4Info (sai::Instantiation::kTor )));
366+
367+ // Expected P4RT AppDb entries.
368+ auto acl_entry = test_lib::AppDbEntryBuilder{}
369+ .SetTableName (" ACL_ACL_PRE_INGRESS_TABLE" )
370+ .SetPriority (10 )
371+ .AddMatchField (" is_ip" , " 0x1" )
372+ .SetAction (" set_vrf" )
373+ .AddActionParam (" vrf_id" , " vrf-1" );
374+ EXPECT_OK (
375+ pdpi::SetMetadataAndSendPiWriteRequest (p4rt_session_.get (), request));
376+ EXPECT_THAT (
377+ p4rt_service_->GetP4rtAppDbTable ().ReadTableEntry (acl_entry.GetKey ()),
378+ IsOkAndHolds (UnorderedElementsAreArray (acl_entry.GetValueMap ())));
379+
380+ // Reset P4RT server
381+ EXPECT_OK (ResetGrpcServerAndClient (/* is_freeze_mode=*/ true ));
382+ // Perform reconciliation
383+ EXPECT_OK (p4rt_service_->GetP4rtServer ().RebuildSwStateAfterWarmboot (
384+ {{" Ethernet4" , " 2" }}, {}, {}, kDeviceId ));
385+ // State Verification
386+ EXPECT_OK (p4rt_service_->GetP4rtServer ().VerifyState ());
387+ // Presence of HOST_STATS|CONFIG entry in STATE DB indicates that P4Info was
388+ // pushed before warm reboot and has been restored during warm bootup.
389+ EXPECT_OK (p4rt_service_->GetHostStatsStateDbTable ().ReadTableEntry (" CONFIG" ));
390+ }
391+
392+ TEST_F (WarmRestartTest, ReconciliationSucceedsWithFixedL3Entries) {
393+ // Set forwarding config and save P4Info file
394+ SetForwardingPipelineConfigRequest pipeline_request =
395+ GetBasicForwardingRequest ();
396+ pipeline_request.set_action (
397+ SetForwardingPipelineConfigRequest::RECONCILE_AND_COMMIT);
398+ *pipeline_request.mutable_config ()->mutable_p4info () =
399+ sai::GetP4Info (sai::Instantiation::kTor );
400+ ASSERT_OK (p4rt_session_->SetForwardingPipelineConfig (pipeline_request));
401+ EXPECT_THAT (GetSavedConfig (),
402+ IsOkAndHolds (EqualsProto (pipeline_request.config ())));
403+
404+ ASSERT_OK (
405+ p4rt_service_->GetP4rtServer ().AddPortTranslation (" Ethernet4" , " 2" ));
406+ // P4 write request for fixed l3 table
407+ ASSERT_OK_AND_ASSIGN (p4::v1::WriteRequest request,
408+ test_lib::PdWriteRequestToPi (
409+ R"pb(
410+ updates {
411+ type: INSERT
412+ table_entry {
413+ router_interface_table_entry {
414+ match { router_interface_id: "16" }
415+ action {
416+ set_port_and_src_mac {
417+ port: "2"
418+ src_mac: "00:02:03:04:05:06"
419+ }
420+ }
421+ }
422+ }
423+ }
424+ )pb" ,
425+ sai::GetIrP4Info (sai::Instantiation::kTor )));
426+
427+ // Expected P4RT AppDb entry.
428+ auto expected_entry = test_lib::AppDbEntryBuilder{}
429+ .SetTableName (" FIXED_ROUTER_INTERFACE_TABLE" )
430+ .AddMatchField (" router_interface_id" , " 16" )
431+ .SetAction (" set_port_and_src_mac" )
432+ .AddActionParam (" port" , " Ethernet4" )
433+ .AddActionParam (" src_mac" , " 00:02:03:04:05:06" );
434+
435+
436+ EXPECT_OK (
437+ pdpi::SetMetadataAndSendPiWriteRequest (p4rt_session_.get (), request));
438+ EXPECT_THAT (
439+ p4rt_service_->GetP4rtAppDbTable ().ReadTableEntry (
440+ expected_entry.GetKey ()),
441+ IsOkAndHolds (UnorderedElementsAreArray (expected_entry.GetValueMap ())));
442+
443+ // Reset P4RT server
444+ EXPECT_OK (ResetGrpcServerAndClient (/* is_freeze_mode=*/ true ));
445+ // Perform reconciliation
446+ EXPECT_OK (p4rt_service_->GetP4rtServer ().RebuildSwStateAfterWarmboot (
447+ {{" Ethernet4" , " 2" }}, {}, {}, kDeviceId ));
448+ // State Verification
449+ EXPECT_OK (p4rt_service_->GetP4rtServer ().VerifyState ());
450+ // Presence of HOST_STATS|CONFIG entry in STATE DB indicates that P4Info was
451+ // pushed before warm reboot and has been restored during warm bootup.
452+ EXPECT_OK (p4rt_service_->GetHostStatsStateDbTable ().ReadTableEntry (" CONFIG" ));
453+ }
454+
455+ TEST_F (WarmRestartTest, ReconciliationFailsP4infoNotFoundAndPushed) {
456+ // The presence of HOST_STATS|CONFIG entry in STATE DB indicates that P4Info
457+ // was pushed before warm reboot.
458+ p4rt_service_->GetHostStatsStateDbTable ().InsertTableEntry (
459+ " CONFIG" , {{" last-configuration-timestamp" ,
460+ absl::StrCat (absl::ToUnixNanos (absl::Now ()))}});
461+ // Reconciliation fails since P4Info is not saved in the file system.
462+ EXPECT_THAT (
463+ p4rt_service_->GetP4rtServer ().RebuildSwStateAfterWarmboot ({}, {}, {}, 1 ),
464+ StatusIs (absl::StatusCode::kInvalidArgument ));
465+ // Fails since P4Info file path is not set.
466+ auto p4runtime_impl = p4rt_service_->BuildP4rtServer (P4RuntimeImplOptions{
467+ .translate_port_ids = true ,
468+ });
469+ EXPECT_THAT (
470+ p4runtime_impl->RebuildSwStateAfterWarmboot ({}, {}, {}, kDeviceId ),
471+ StatusIs (absl::StatusCode::kFailedPrecondition ));
472+ }
473+
474+ TEST_F (WarmRestartTest, ReconciliationSucceedsP4infoNotFoundAndNotPushed) {
475+ // The absence of HOST_STATS|CONFIG entry in STATE DB indicates that P4Info
476+ // wasn't pushed before warm reboot.
477+ EXPECT_THAT (
478+ p4rt_service_->GetHostStatsStateDbTable ().ReadTableEntry (" CONFIG" ),
479+ StatusIs (absl::StatusCode::kNotFound ));
480+ // P4Info reconciliation should succeed when P4Info wasn't pushed before warm
481+ // reboot, and thus it isn't present after warm reboot.
482+ EXPECT_OK (p4rt_service_->GetP4rtServer ().RebuildSwStateAfterWarmboot (
483+ {{" Ethernet4" , " 2" }}, {}, {}, kDeviceId ));
308484}
309485
310486TEST_F (WarmRestartTest, ReconciliationFailsWhenDbEntryInvalid) {
0 commit comments