diff --git a/SOURCES/openvswitch-2.16.0.patch b/SOURCES/openvswitch-2.16.0.patch
index a79a205..c82ee65 100644
--- a/SOURCES/openvswitch-2.16.0.patch
+++ b/SOURCES/openvswitch-2.16.0.patch
@@ -532,6 +532,163 @@ index 2610d626a0..7f1d2fb412 100644
      }
  
      ctx->hash = OvsCtHashKey(&ctx->key);
+diff --git a/datapath-windows/ovsext/PacketIO.c b/datapath-windows/ovsext/PacketIO.c
+index cc0840704a..2a206305ec 100644
+--- a/datapath-windows/ovsext/PacketIO.c
++++ b/datapath-windows/ovsext/PacketIO.c
+@@ -45,7 +45,9 @@ extern NDIS_STRING ovsExtFriendlyNameUC;
+ 
+ static VOID OvsFinalizeCompletionList(OvsCompletionList *completionList);
+ static VOID OvsCompleteNBLIngress(POVS_SWITCH_CONTEXT switchContext,
+-                    PNET_BUFFER_LIST netBufferLists, ULONG sendCompleteFlags);
++                                  PNET_BUFFER_LIST netBufferLists,
++                                  ULONG sendCompleteFlags,
++                                  BOOLEAN isSendComplete);
+ 
+ VOID
+ OvsInitCompletionList(OvsCompletionList *completionList,
+@@ -155,7 +157,7 @@ OvsSendNBLIngress(POVS_SWITCH_CONTEXT switchContext,
+         OvsReportNBLIngressError(switchContext, netBufferLists, &filterReason,
+                                  NDIS_STATUS_PAUSED);
+         OvsCompleteNBLIngress(switchContext, netBufferLists,
+-                              sendCompleteFlags);
++                              sendCompleteFlags, FALSE);
+         return;
+     }
+ 
+@@ -175,6 +177,79 @@ OvsSendNBLIngress(POVS_SWITCH_CONTEXT switchContext,
+                             NDIS_DEFAULT_PORT_NUMBER, sendFlags);
+ }
+ 
++static __inline BOOLEAN
++OvsCheckNBLSingleSource(PNET_BUFFER_LIST netBufferLists)
++{
++    UINT32 sourcePortId = 0;
++    BOOLEAN singleSource = TRUE;
++    PNET_BUFFER_LIST curNbl = netBufferLists;
++    PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO info;
++
++    while (curNbl != NULL) {
++        info = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(curNbl);
++        if (info == NULL) {
++            /* We are not able to determine the source port ID */
++            singleSource = FALSE;
++            OVS_LOG_INFO("nbl %p has no source port", curNbl);
++            break;
++        }
++        if (curNbl == netBufferLists) {
++            sourcePortId = info->SourcePortId;
++        } else if (info->SourcePortId != sourcePortId) {
++            singleSource = FALSE;
++            OVS_LOG_INFO("Source port in nbl %p is %u, not from %u",
++                         curNbl, info->SourcePortId, sourcePortId);
++            break;
++        }
++        curNbl = NET_BUFFER_LIST_NEXT_NBL(curNbl);
++    }
++
++    return singleSource;
++}
++
++/*
++ * SendNetBufferListsCompleteHandler releases the NetBufferLists with flag
++ * NDIS_SEND_COMPLETE_FLAGS_SWITCH_SINGLE_SOURCE if all the NBLs have same
++ * source port, for cloned NBLs, source port might be changed, although the
++ * cloned NBLs have same source port, there parent NBLs may have different
++ * source ports, so we should have a check before passing the flag to
++ * NdisFSendNetBufferListsComplete.
++ */
++static __inline VOID
++OvsCompleteUpperLayerNBL(NDIS_HANDLE ndisHandle,
++                         PNET_BUFFER_LIST netBufferLists,
++                         ULONG sendCompleteFlags,
++                         BOOLEAN isSendComplete)
++{
++    BOOLEAN singleSource = TRUE;
++    PNET_BUFFER_LIST curNbl, nextNbl;
++
++    /* To check whether the NBLs are from the same source port */
++    if (isSendComplete &&
++        (sendCompleteFlags & NDIS_SEND_COMPLETE_FLAGS_SWITCH_SINGLE_SOURCE)) {
++        singleSource = OvsCheckNBLSingleSource(netBufferLists);
++    }
++
++    if (singleSource) {
++        NdisFSendNetBufferListsComplete(ndisHandle,
++                                        netBufferLists,
++                                        sendCompleteFlags);
++    } else {
++        /*
++         * Not from a single source port, releasing the NBls without flag
++         * NDIS_SEND_COMPLETE_FLAGS_SWITCH_SINGLE_SOURCE doesn't help, so
++         * let's release them one by one.
++         */
++        for (curNbl = netBufferLists; curNbl != NULL; curNbl = nextNbl) {
++            nextNbl = NET_BUFFER_LIST_NEXT_NBL(curNbl);
++            NET_BUFFER_LIST_NEXT_NBL(curNbl) = NULL;
++            NdisFSendNetBufferListsComplete(ndisHandle,
++                                            curNbl,
++                                            sendCompleteFlags);
++        }
++    }
++}
++
+ static __inline VOID
+ OvsStartNBLIngressError(POVS_SWITCH_CONTEXT switchContext,
+                         PNET_BUFFER_LIST nblList,
+@@ -184,8 +259,8 @@ OvsStartNBLIngressError(POVS_SWITCH_CONTEXT switchContext,
+ {
+     ASSERT(error);
+     OvsReportNBLIngressError(switchContext, nblList, filterReason, error);
+-    NdisFSendNetBufferListsComplete(switchContext->NdisFilterHandle, nblList,
+-                                    sendCompleteFlags);
++    OvsCompleteUpperLayerNBL(switchContext->NdisFilterHandle, nblList,
++                             sendCompleteFlags, FALSE);
+ }
+ 
+ static VOID
+@@ -427,7 +502,8 @@ OvsExtSendNBL(NDIS_HANDLE filterModuleContext,
+ static VOID
+ OvsCompleteNBLIngress(POVS_SWITCH_CONTEXT switchContext,
+                       PNET_BUFFER_LIST netBufferLists,
+-                      ULONG sendCompleteFlags)
++                      ULONG sendCompleteFlags,
++                      BOOLEAN isSendComplete)
+ {
+     PNET_BUFFER_LIST curNbl = NULL, nextNbl = NULL;
+     OvsCompletionList newList;
+@@ -449,8 +525,10 @@ OvsCompleteNBLIngress(POVS_SWITCH_CONTEXT switchContext,
+ 
+     /* Complete the NBL's that were sent by the upper layer. */
+     if (newList.dropNbl != NULL) {
+-        NdisFSendNetBufferListsComplete(switchContext->NdisFilterHandle, newList.dropNbl,
+-                                        sendCompleteFlags);
++        OvsCompleteUpperLayerNBL(switchContext->NdisFilterHandle,
++                                 newList.dropNbl,
++                                 sendCompleteFlags,
++                                 isSendComplete);
+     }
+ }
+ 
+@@ -466,7 +544,7 @@ OvsExtSendNBLComplete(NDIS_HANDLE filterModuleContext,
+                       ULONG sendCompleteFlags)
+ {
+     OvsCompleteNBLIngress((POVS_SWITCH_CONTEXT)filterModuleContext,
+-                          netBufferLists, sendCompleteFlags);
++                          netBufferLists, sendCompleteFlags, TRUE);
+ }
+ 
+ 
+@@ -476,7 +554,8 @@ OvsFinalizeCompletionList(OvsCompletionList *completionList)
+     if (completionList->dropNbl != NULL) {
+         OvsCompleteNBLIngress(completionList->switchContext,
+                               completionList->dropNbl,
+-                              completionList->sendCompleteFlags);
++                              completionList->sendCompleteFlags,
++                              FALSE);
+ 
+         completionList->dropNbl = NULL;
+         completionList->dropNblNext = &completionList->dropNbl;
 diff --git a/datapath-windows/ovsext/Recirc.c b/datapath-windows/ovsext/Recirc.c
 index 2febf060dd..7a688c8742 100644
 --- a/datapath-windows/ovsext/Recirc.c
diff --git a/SPECS/openvswitch2.16.spec b/SPECS/openvswitch2.16.spec
index 2284162..3a5ef72 100644
--- a/SPECS/openvswitch2.16.spec
+++ b/SPECS/openvswitch2.16.spec
@@ -57,7 +57,7 @@ Summary: Open vSwitch
 Group: System Environment/Daemons daemon/database/utilities
 URL: http://www.openvswitch.org/
 Version: 2.16.0
-Release: 76%{?dist}
+Release: 77%{?dist}
 
 # Nearly all of openvswitch is ASL 2.0.  The bugtool is LGPLv2+, and the
 # lib/sflow*.[ch] files are SISSL
@@ -699,6 +699,12 @@ exit 0
 %endif
 
 %changelog
+* Wed May 25 2022 Open vSwitch CI <ovs-ci@redhat.com> - 2.16.0-77
+- Merging upstream branch-2.16 [RH git: 3e3d3725d3]
+    Commit list:
+    72bad27674 Carefully release NBL in Windows
+
+
 * Wed May 18 2022 Open vSwitch CI <ovs-ci@redhat.com> - 2.16.0-76
 - Merging upstream branch-2.16 [RH git: 72426100fe]
     Commit list: