[edk2-devel] [edk2-redfish-client][PATCH] RedfishClientPkg: Add ETag PCD and revise Redfish ETag functions

Chang, Abner via groups.io posted 1 patch 4 months ago
Failed in applying to current master (apply log)
There is a newer version of this series
RedfishClientPkg/RedfishClientPkg.dec         |   2 +
.../RedfishFeatureUtilityLib.inf              |   1 +
.../Library/RedfishFeatureUtilityLib.h        |  46 +++-
.../RedfishFeatureUtilityLib.c                | 212 ++++++++++++------
4 files changed, 180 insertions(+), 81 deletions(-)
[edk2-devel] [edk2-redfish-client][PATCH] RedfishClientPkg: Add ETag PCD and revise Redfish ETag functions
Posted by Chang, Abner via groups.io 4 months ago
From: Abner Chang <abner.chang@amd.com>

Add PCD to disable ETag capability for the case Redfish
service doesn't support ETag.

Signed-off-by: Abner Chang <abner.chang@amd.com>
Cc: Nickle Wang <nicklew@nvidia.com>
Cc: Igor Kulchytskyy <igork@ami.com>
Cc: Mike Maslenkin <mike.maslenkin@gmail.com>
---
 RedfishClientPkg/RedfishClientPkg.dec         |   2 +
 .../RedfishFeatureUtilityLib.inf              |   1 +
 .../Library/RedfishFeatureUtilityLib.h        |  46 +++-
 .../RedfishFeatureUtilityLib.c                | 212 ++++++++++++------
 4 files changed, 180 insertions(+), 81 deletions(-)

diff --git a/RedfishClientPkg/RedfishClientPkg.dec b/RedfishClientPkg/RedfishClientPkg.dec
index 5f8a03501d..155eea9812 100644
--- a/RedfishClientPkg/RedfishClientPkg.dec
+++ b/RedfishClientPkg/RedfishClientPkg.dec
@@ -75,6 +75,8 @@
   gEfiRedfishClientPkgTokenSpaceGuid.PcdDefaultRedfishVersion|L"v1"|VOID*|0x10000004
   ## The number of seconds that the firmware will wait before system reboot
   gEfiRedfishClientPkgTokenSpaceGuid.PcdRedfishSystemRebootTimeout|5|UINT16|0x20000002
+  ## Default capability of Redfish service side ETAG support
+  gEfiRedfishClientPkgTokenSpaceGuid.PcdRedfishServiceEtagSupported|TRUE|BOOLEAN|0x10000005
 
 [PcdsDynamicEx]
   ## The flag used to indicate that system reboot is required due to system configuration change
diff --git a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.inf b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.inf
index fd66b8ac34..681c121a13 100644
--- a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.inf
+++ b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.inf
@@ -53,6 +53,7 @@
 
 [Pcd]
   gEfiRedfishClientPkgTokenSpaceGuid.PcdRedfishSystemRebootRequired
+  gEfiRedfishClientPkgTokenSpaceGuid.PcdRedfishServiceEtagSupported
 
 [Guids]
 
diff --git a/RedfishClientPkg/Include/Library/RedfishFeatureUtilityLib.h b/RedfishClientPkg/Include/Library/RedfishFeatureUtilityLib.h
index 24f0ad2447..2f0833632c 100644
--- a/RedfishClientPkg/Include/Library/RedfishFeatureUtilityLib.h
+++ b/RedfishClientPkg/Include/Library/RedfishFeatureUtilityLib.h
@@ -100,7 +100,7 @@ CopyConfiglanguageList (
 
 /**
 
-  Get number of node from the string. Node is seperated by '/'.
+  Get number of node from the string. Node is separated by '/'.
 
   @param[in]  NodeString             The node string to parse.
 
@@ -578,6 +578,19 @@ GetEtagWithUri (
   IN  EFI_STRING  Uri
   );
 
+/**
+
+  This function returns a boolean of ETAG support on Redfish service side.
+
+  @retval     TRUE    ETAG is supported on Redfish service.
+  @retval     FALSE   ETAG is not supported on Redfish service.
+
+**/
+BOOLEAN
+CheckIsServerEtagSupported (
+  VOID
+  );
+
 /**
 
   Get @odata.id from give HTTP payload. It's call responsibility to release returned buffer.
@@ -950,22 +963,33 @@ CompareRedfishPropertyVagueValues (
   );
 
 /**
+  Find "ETag" from either HTTP header or Redfish response.
 
-  Find "ETag" and "Location" from either HTTP header or Redfish response.
+  @param[in]  Response        HTTP response
+  @param[out] Etag            String buffer to return ETag
 
-  @param[in]  Response    HTTP response
-  @param[out] Etag        String buffer to return ETag
-  @param[out] Location    String buffer to return Location
+  @retval  EFI_SUCCESS            ETag is returned in Etag
+  @retval  EFI_UNSUPPORTED        ETag is unsupported
+  @retval  EFI_INVALID_PARAMETER  Response, Etag or both are NULL.
 
-  @retval     EFI_SUCCESS     Data is found and returned.
-  @retval     Others          Errors occur.
+**/
+EFI_STATUS
+GetHttpResponseEtag (
+  IN  REDFISH_RESPONSE  *Response,
+  OUT CHAR8             **Etag
+  );
+
+/**
+  Find "Location" from either HTTP header or Redfish response.
+
+  @param[in]  Response        HTTP response
+  @param[out] Location        String buffer to return Location
 
 **/
 EFI_STATUS
-GetEtagAndLocation (
-  IN  REDFISH_RESPONSE *Response,
-  OUT CHAR8 **Etag, OPTIONAL
-  OUT EFI_STRING        *Location    OPTIONAL
+GetHttpResponseLocation (
+  IN  REDFISH_RESPONSE  *Response,
+  OUT EFI_STRING        *Location
   );
 
 /**
diff --git a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.c b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.c
index 01c054ae3b..a77758d0a2 100644
--- a/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.c
+++ b/RedfishClientPkg/Library/RedfishFeatureUtilityLib/RedfishFeatureUtilityLib.c
@@ -133,6 +133,11 @@ SetEtagFromUri (
   REDFISH_RESPONSE  Response;
   EFI_STRING        PendingSettingUri;
 
+  if (!CheckIsServerEtagSupported ()) {
+    DEBUG ((DEBUG_INFO, "%a: WARNING - ETAG is not supported\n", __func__));
+    return EFI_SUCCESS;
+  }
+
   if ((RedfishService == NULL) || IS_EMPTY_STRING (Uri)) {
     return EFI_INVALID_PARAMETER;
   }
@@ -156,9 +161,9 @@ SetEtagFromUri (
   //
   // Find etag in HTTP response header
   //
-  Status = GetEtagAndLocation (&Response, &Etag, NULL);
-  if (EFI_ERROR (Status)) {
-    DEBUG ((DEBUG_ERROR, "%a: failed to get ETag from HTTP header\n", __func__));
+  Status = GetHttpResponseEtag (&Response, &Etag);
+  if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+    DEBUG ((DEBUG_ERROR, "%a: Failed to get ETag from HTTP header\n", __func__));
     Status = EFI_NOT_FOUND;
     goto ON_RELEASE;
   }
@@ -240,6 +245,11 @@ SetEtagWithUri (
   EFI_STATUS  Status;
   CHAR8       *AsciiUri;
 
+  if (!CheckIsServerEtagSupported ()) {
+    DEBUG ((DEBUG_INFO, "%a: WARNING - ETAG is not supported\n", __func__));
+    return EFI_SUCCESS;
+  }
+
   if (IS_EMPTY_STRING (EtagStr) || IS_EMPTY_STRING (Uri)) {
     return EFI_INVALID_PARAMETER;
   }
@@ -285,6 +295,11 @@ GetEtagWithUri (
     return NULL;
   }
 
+  if (!CheckIsServerEtagSupported ()) {
+    DEBUG ((DEBUG_INFO, "%a: WARNING - ETAG is not supported\n", __func__));
+    return NULL;
+  }
+
   Status = RedfishLocateProtocol ((VOID **)&mEtagProtocol, &gEdkIIRedfishETagProtocolGuid);
   if (EFI_ERROR (Status)) {
     DEBUG ((DEBUG_ERROR, "%a: fail to locate gEdkIIRedfishETagProtocolGuid: %r\n", __func__, Status));
@@ -1785,44 +1800,39 @@ RedfishFeatureGetUnifiedArrayTypeConfigureLang (
 }
 
 /**
+  Find "ETag" from either HTTP header or Redfish response.
 
-  Find "ETag" and "Location" from either HTTP header or Redfish response.
+  @param[in]  Response        HTTP response
+  @param[out] Etag            String buffer to return ETag
 
-  @param[in]  Response    HTTP response
-  @param[out] Etag        String buffer to return ETag
-  @param[out] Location    String buffer to return Location
-
-  @retval     EFI_SUCCESS     Data is found and returned.
-  @retval     Others          Errors occur.
+  @retval  EFI_SUCCESS            ETag is returned in Etag
+  @retval  EFI_UNSUPPORTED        ETag is unsupported
+  @retval  EFI_INVALID_PARAMETER  Response, Etag or both are NULL.
 
 **/
 EFI_STATUS
-GetEtagAndLocation (
-  IN  REDFISH_RESPONSE *Response,
-  OUT CHAR8 **Etag, OPTIONAL
-  OUT EFI_STRING        *Location    OPTIONAL
+GetHttpResponseEtag (
+  IN  REDFISH_RESPONSE  *Response,
+  OUT CHAR8             **Etag
   )
 {
+  EFI_STATUS        Status;
   EDKII_JSON_VALUE  JsonValue;
   EDKII_JSON_VALUE  OdataValue;
   CHAR8             *OdataString;
-  CHAR8             *AsciiLocation;
   EFI_HTTP_HEADER   *Header;
-  EFI_STATUS        Status;
 
-  if (Response == NULL) {
+  if ((Response == NULL) || (Etag == NULL)) {
     return EFI_INVALID_PARAMETER;
   }
 
-  if ((Etag == NULL) && (Location == NULL)) {
-    return EFI_SUCCESS;
-  }
-
   Status = EFI_SUCCESS;
-
-  if (Etag != NULL) {
-    *Etag = NULL;
-
+  *Etag  = NULL;
+  if (!CheckIsServerEtagSupported ()) {
+    // Don't look for ETAG header or property in this case.
+    DEBUG ((DEBUG_INFO, "%a: WARNING - No ETag support on Redfish service.\n", __func__));
+    return EFI_UNSUPPORTED;
+  } else {
     if (*(Response->StatusCode) == HTTP_STATUS_200_OK) {
       Header = HttpFindHeader (Response->HeaderCount, Response->Headers, HTTP_HEADER_ETAG);
       if (Header != NULL) {
@@ -1852,51 +1862,94 @@ GetEtagAndLocation (
 
     if (*Etag == NULL) {
       Status = EFI_NOT_FOUND;
+      DEBUG ((DEBUG_ERROR, "%a: Failed to retrieve ETag from HTTP response paylaod.\n", __func__));
     }
   }
 
-  if (Location != NULL) {
-    *Location     = NULL;
-    AsciiLocation = NULL;
+  return Status;
+}
 
-    if (*(Response->StatusCode) == HTTP_STATUS_200_OK) {
-      Header = HttpFindHeader (Response->HeaderCount, Response->Headers, HTTP_HEADER_LOCATION);
-      if (Header != NULL) {
-        AsciiLocation = AllocateCopyPool (AsciiStrSize (Header->FieldValue), Header->FieldValue);
-        ASSERT (AsciiLocation != NULL);
-      }
+/**
+  Find "Location" from either HTTP header or Redfish response.
+
+  @param[in]  Response        HTTP response
+  @param[out] Location        String buffer to return Location
+
+**/
+EFI_STATUS
+GetHttpResponseLocation (
+  IN  REDFISH_RESPONSE  *Response,
+  OUT EFI_STRING        *Location
+  )
+{
+  EFI_STATUS        Status;
+  EDKII_JSON_VALUE  JsonValue;
+  EDKII_JSON_VALUE  OdataValue;
+  CHAR8             *OdataString;
+  CHAR8             *AsciiLocation;
+  EFI_HTTP_HEADER   *Header;
+
+  if ((Response == NULL) || (Location == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status        = EFI_SUCCESS;
+  *Location     = NULL;
+  AsciiLocation = NULL;
+  if (*(Response->StatusCode) == HTTP_STATUS_200_OK) {
+    Header = HttpFindHeader (Response->HeaderCount, Response->Headers, HTTP_HEADER_LOCATION);
+    if (Header != NULL) {
+      AsciiLocation = AllocateCopyPool (AsciiStrSize (Header->FieldValue), Header->FieldValue);
+      ASSERT (AsciiLocation != NULL);
     }
+  }
 
-    //
-    // No header is returned. Search payload for location.
-    //
-    if ((*Location == NULL) && (Response->Payload != NULL)) {
-      JsonValue = RedfishJsonInPayload (Response->Payload);
-      if (JsonValue != NULL) {
-        OdataValue = JsonObjectGetValue (JsonValueGetObject (JsonValue), "@odata.id");
-        if (OdataValue != NULL) {
-          OdataString = (CHAR8 *)JsonValueGetAsciiString (OdataValue);
-          if (OdataString != NULL) {
-            AsciiLocation = AllocateCopyPool (AsciiStrSize (OdataString), OdataString);
-            ASSERT (AsciiLocation != NULL);
-          }
+  //
+  // No header is returned. Search payload for location.
+  //
+  if ((*Location == NULL) && (Response->Payload != NULL)) {
+    JsonValue = RedfishJsonInPayload (Response->Payload);
+    if (JsonValue != NULL) {
+      OdataValue = JsonObjectGetValue (JsonValueGetObject (JsonValue), "@odata.id");
+      if (OdataValue != NULL) {
+        OdataString = (CHAR8 *)JsonValueGetAsciiString (OdataValue);
+        if (OdataString != NULL) {
+          AsciiLocation = AllocateCopyPool (AsciiStrSize (OdataString), OdataString);
+          ASSERT (AsciiLocation != NULL);
         }
-
-        JsonValueFree (JsonValue);
       }
-    }
 
-    if (AsciiLocation != NULL) {
-      *Location = StrAsciiToUnicode (AsciiLocation);
-      FreePool (AsciiLocation);
-    } else {
-      Status = EFI_NOT_FOUND;
+      JsonValueFree (JsonValue);
     }
   }
 
+  if (AsciiLocation != NULL) {
+    *Location = StrAsciiToUnicode (AsciiLocation);
+    FreePool (AsciiLocation);
+  } else {
+    Status = EFI_NOT_FOUND;
+    DEBUG ((DEBUG_ERROR, "%a: Failed to retrieve Location from HTTP response paylaod.\n", __func__));
+  }
+
   return Status;
 }
 
+/**
+
+  This function returns a boolean of ETAG support on Redfish service side.
+
+  @retval     TRUE    ETAG is supported on Redfish service.
+  @retval     FALSE   ETAG is not supported on Redfish service.
+
+**/
+BOOLEAN
+CheckIsServerEtagSupported (
+  VOID
+  )
+{
+  return FixedPcdGetBool (PcdRedfishServiceEtagSupported);
+}
+
 /**
 
   Create HTTP payload and send them to redfish service with PATCH method.
@@ -1915,15 +1968,15 @@ CreatePayloadToPatchResource (
   IN  REDFISH_SERVICE  *Service,
   IN  REDFISH_PAYLOAD  *TargetPayload,
   IN  CHAR8            *Json,
-  OUT CHAR8            **Etag
+  OUT CHAR8            **Etag OPTIONAL
   )
 {
   REDFISH_PAYLOAD   Payload;
   EDKII_JSON_VALUE  ResourceJsonValue;
-  REDFISH_RESPONSE  PostResponse;
+  REDFISH_RESPONSE  PatchResponse;
   EFI_STATUS        Status;
 
-  if ((Service == NULL) || (TargetPayload == NULL) || IS_EMPTY_STRING (Json) || (Etag == NULL)) {
+  if ((Service == NULL) || (TargetPayload == NULL) || IS_EMPTY_STRING (Json)) {
     return EFI_INVALID_PARAMETER;
   }
 
@@ -1935,8 +1988,8 @@ CreatePayloadToPatchResource (
     goto EXIT_FREE_JSON_VALUE;
   }
 
-  ZeroMem (&PostResponse, sizeof (REDFISH_RESPONSE));
-  Status = RedfishPatchToPayload (TargetPayload, Payload, &PostResponse);
+  ZeroMem (&PatchResponse, sizeof (REDFISH_RESPONSE));
+  Status = RedfishPatchToPayload (TargetPayload, Payload, &PatchResponse);
   if (EFI_ERROR (Status)) {
     DEBUG ((DEBUG_ERROR, "%a:%d Failed to PATCH payload to Redfish service.\n", __func__, __LINE__));
 
@@ -1944,7 +1997,7 @@ CreatePayloadToPatchResource (
     DEBUG ((DEBUG_ERROR, "%a: Request:\n", __func__));
     DumpRedfishPayload (DEBUG_ERROR, Payload);
     DEBUG ((DEBUG_ERROR, "%a: Response:\n", __func__));
-    DumpRedfishResponse (__func__, DEBUG_ERROR, &PostResponse);
+    DumpRedfishResponse (__func__, DEBUG_ERROR, &PatchResponse);
     DEBUG_CODE_END ();
     goto EXIT_FREE_JSON_VALUE;
   }
@@ -1952,16 +2005,20 @@ CreatePayloadToPatchResource (
   //
   // Find ETag
   //
-  Status = GetEtagAndLocation (&PostResponse, Etag, NULL);
-  if (EFI_ERROR (Status)) {
+  Status = GetHttpResponseEtag (&PatchResponse, Etag);
+  if (Status == EFI_UNSUPPORTED) {
+    Status = EFI_SUCCESS;
+    DEBUG ((DEBUG_INFO, "%a: WARNING - ETAG is not supported on Redfish service.\n", __func__));
+  } else {
     Status = EFI_DEVICE_ERROR;
+    DEBUG ((DEBUG_ERROR, "%a: Fail to get Location header nor proerty from HTTP response payload.\n", __func__));
   }
 
   RedfishFreeResponse (
-    PostResponse.StatusCode,
-    PostResponse.HeaderCount,
-    PostResponse.Headers,
-    PostResponse.Payload
+    PatchResponse.StatusCode,
+    PatchResponse.HeaderCount,
+    PatchResponse.Headers,
+    PatchResponse.Payload
     );
 
 EXIT_FREE_JSON_VALUE:
@@ -1994,7 +2051,7 @@ CreatePayloadToPostResource (
   IN  REDFISH_PAYLOAD  *TargetPayload,
   IN  CHAR8            *Json,
   OUT EFI_STRING       *Location,
-  OUT CHAR8            **Etag
+  OUT CHAR8            **Etag OPTIONAL
   )
 {
   REDFISH_PAYLOAD   Payload;
@@ -2002,7 +2059,7 @@ CreatePayloadToPostResource (
   REDFISH_RESPONSE  PostResponse;
   EFI_STATUS        Status;
 
-  if ((Service == NULL) || (TargetPayload == NULL) || IS_EMPTY_STRING (Json) || (Location == NULL) || (Etag == NULL)) {
+  if ((Service == NULL) || (TargetPayload == NULL) || IS_EMPTY_STRING (Json) || (Location == NULL)) {
     return EFI_INVALID_PARAMETER;
   }
 
@@ -2029,12 +2086,22 @@ CreatePayloadToPostResource (
     goto EXIT_FREE_JSON_VALUE;
   }
 
+  Status = GetHttpResponseEtag (&PostResponse, Etag);
+  if (Status == EFI_UNSUPPORTED) {
+    Status = EFI_SUCCESS;
+    DEBUG ((DEBUG_INFO, "%a: WARNING - ETAG is not supported on Redfish service.\n", __func__));
+  } else if (EFI_ERROR (Status)) {
+    Status = EFI_DEVICE_ERROR;
+    DEBUG ((DEBUG_ERROR, "%a: Fail to get ETAG header nor ETAG propertyfrom HTTP response payload.\n", __func__));
+  }
+
   //
   // per Redfish spec. the URL of new resource will be returned in "Location" header.
   //
-  Status = GetEtagAndLocation (&PostResponse, Etag, Location);
+  Status = GetHttpResponseLocation (&PostResponse, Location);
   if (EFI_ERROR (Status)) {
     Status = EFI_DEVICE_ERROR;
+    DEBUG ((DEBUG_ERROR, "%a: Fail to get Location header nor proerty from HTTP response payload.\n", __func__));
   }
 
   RedfishFreeResponse (
@@ -3176,6 +3243,11 @@ CheckEtag (
 {
   CHAR8  *EtagInDb;
 
+  if (!CheckIsServerEtagSupported ()) {
+    DEBUG ((DEBUG_INFO, "%a: WARNING - ETAG is not supported, always returns FALSE to consume resource (Performance would be reduced).\n", __func__));
+    return FALSE;
+  }
+
   if (IS_EMPTY_STRING (Uri)) {
     return FALSE;
   }
-- 
2.37.1.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#113059): https://edk2.groups.io/g/devel/message/113059
Mute This Topic: https://groups.io/mt/103498331/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-