@@ -853,7 +853,7 @@ CxPlatDpRawInterfaceInitialize(
853853
854854_IRQL_requires_max_ (PASSIVE_LEVEL )
855855_Requires_lock_held_ (Interface -> RuleLock )
856- void
856+ QUIC_STATUS
857857CxPlatDpRawInterfaceUpdateRules (
858858 _In_ XDP_INTERFACE * Interface
859859 )
@@ -864,6 +864,8 @@ CxPlatDpRawInterfaceUpdateRules(
864864 .SubLayer = XDP_HOOK_INSPECT ,
865865 };
866866
867+ QUIC_STATUS ReturnStatus = QUIC_STATUS_SUCCESS ;
868+
867869 for (uint32_t i = 0 ; i < Interface -> QueueCount ; i ++ ) {
868870
869871 CXPLAT_QUEUE * Queue = & Interface -> Queues [i ];
@@ -882,16 +884,14 @@ CxPlatDpRawInterfaceUpdateRules(
882884 Interface -> RuleCount ,
883885 & NewRxProgram );
884886 if (QUIC_FAILED (Status )) {
885- //
886- // TODO - Figure out how to better handle failure and revert changes.
887- // This will likely require working with XDP to get an improved API;
888- // possibly to update all queues at once.
889- //
890887 QuicTraceEvent (
891888 LibraryErrorStatus ,
892889 "[ lib] ERROR, %u, %s." ,
893890 Status ,
894891 "XdpCreateProgram" );
892+ if (QUIC_SUCCEEDED (ReturnStatus )) {
893+ ReturnStatus = Status ;
894+ }
895895 continue ;
896896 }
897897
@@ -901,10 +901,12 @@ CxPlatDpRawInterfaceUpdateRules(
901901
902902 Queue -> RxProgram = NewRxProgram ;
903903 }
904+
905+ return ReturnStatus ;
904906}
905907
906908_IRQL_requires_max_ (PASSIVE_LEVEL )
907- void
909+ QUIC_STATUS
908910CxPlatDpRawInterfaceAddRules (
909911 _In_ XDP_INTERFACE * Interface ,
910912 _In_reads_ (Count ) const XDP_RULE * Rules ,
@@ -914,6 +916,8 @@ CxPlatDpRawInterfaceAddRules(
914916#pragma warning(push)
915917#pragma warning(disable:6386) // Buffer overrun while writing to 'NewRules' - FALSE POSITIVE
916918
919+ QUIC_STATUS Status ;
920+
917921 CxPlatLockAcquire (& Interface -> RuleLock );
918922 // TODO - Don't always allocate a new array?
919923
@@ -923,7 +927,7 @@ CxPlatDpRawInterfaceAddRules(
923927 "[ lib] ERROR, %s." ,
924928 "No more room for rules" );
925929 CxPlatLockRelease (& Interface -> RuleLock );
926- return ;
930+ return QUIC_STATUS_BUFFER_TOO_SMALL ;
927931 }
928932
929933 const size_t OldSize = sizeof (XDP_RULE ) * (size_t )Interface -> RuleCount ;
@@ -937,7 +941,7 @@ CxPlatDpRawInterfaceAddRules(
937941 "XDP_RULE" ,
938942 NewSize );
939943 CxPlatLockRelease (& Interface -> RuleLock );
940- return ;
944+ return QUIC_STATUS_OUT_OF_MEMORY ;
941945 }
942946
943947 if (Interface -> RuleCount > 0 ) {
@@ -952,11 +956,13 @@ CxPlatDpRawInterfaceAddRules(
952956 }
953957 Interface -> Rules = NewRules ;
954958
955- CxPlatDpRawInterfaceUpdateRules (Interface );
959+ Status = CxPlatDpRawInterfaceUpdateRules (Interface );
956960
957961 CxPlatLockRelease (& Interface -> RuleLock );
958962
959963#pragma warning(pop)
964+
965+ return Status ;
960966}
961967
962968_IRQL_requires_max_ (PASSIVE_LEVEL )
@@ -1423,12 +1429,13 @@ CxPlatDpRawClearPortBit(
14231429}
14241430
14251431_IRQL_requires_max_ (PASSIVE_LEVEL )
1426- void
1432+ QUIC_STATUS
14271433CxPlatDpRawPlumbRulesOnSocket (
14281434 _In_ CXPLAT_SOCKET_RAW * Socket ,
14291435 _In_ BOOLEAN IsCreated
14301436 )
14311437{
1438+ QUIC_STATUS Status = QUIC_STATUS_SUCCESS ;
14321439 XDP_DATAPATH * Xdp = (XDP_DATAPATH * )Socket -> RawDatapath ;
14331440 if (Socket -> Wildcard ) {
14341441 XDP_RULE Rules [5 ] = {0 };
@@ -1504,7 +1511,17 @@ CxPlatDpRawPlumbRulesOnSocket(
15041511 for (Entry = Xdp -> Interfaces .Flink ; Entry != & Xdp -> Interfaces ; Entry = Entry -> Flink ) {
15051512 XDP_INTERFACE * Interface = CONTAINING_RECORD (Entry , XDP_INTERFACE , Link );
15061513 if (IsCreated ) {
1507- CxPlatDpRawInterfaceAddRules (Interface , Rules , RulesSize );
1514+ QUIC_STATUS AddStatus = CxPlatDpRawInterfaceAddRules (Interface , Rules , RulesSize );
1515+ if (QUIC_FAILED (AddStatus )) {
1516+ //
1517+ // Stop on first failure and propagate. The caller is
1518+ // responsible for invoking this function again with
1519+ // IsCreated=FALSE to roll back any rules already
1520+ // installed on previous interfaces.
1521+ //
1522+ Status = AddStatus ;
1523+ break ;
1524+ }
15081525 } else {
15091526 CxPlatDpRawInterfaceRemoveRules (Interface , Rules , RulesSize );
15101527 }
@@ -1566,14 +1583,37 @@ CxPlatDpRawPlumbRulesOnSocket(
15661583 "Allocation of '%s' failed. (%llu bytes)" ,
15671584 "PortSet" ,
15681585 XDP_PORT_SET_BUFFER_SIZE );
1569- return ;
1586+ Status = QUIC_STATUS_OUT_OF_MEMORY ;
1587+ break ;
15701588 }
15711589 CxPlatDpRawSetPortBit (
15721590 (uint8_t * )NewRule .Pattern .IpPortSet .PortSet .PortSet ,
15731591 Socket -> LocalAddress .Ipv4 .sin_port );
15741592 memcpy (
15751593 & NewRule .Pattern .IpPortSet .Address , IpAddress , IpAddressSize );
1576- CxPlatDpRawInterfaceAddRules (Interface , & NewRule , 1 );
1594+ QUIC_STATUS AddStatus = CxPlatDpRawInterfaceAddRules (Interface , & NewRule , 1 );
1595+ if (QUIC_FAILED (AddStatus )) {
1596+ Status = AddStatus ;
1597+ if (AddStatus == QUIC_STATUS_OUT_OF_MEMORY ||
1598+ AddStatus == QUIC_STATUS_BUFFER_TOO_SMALL ) {
1599+ //
1600+ // The rule was not copied into Interface->Rules — we still own
1601+ // the PortSet buffer and must free it. On XdpCreateProgram failure,
1602+ // the rule was already added to Interface->Rules which now owns
1603+ // the PortSet buffer; do not free it in that case.
1604+ //
1605+ CxPlatFree (
1606+ (uint8_t * )NewRule .Pattern .IpPortSet .PortSet .PortSet ,
1607+ PORT_SET_TAG );
1608+ }
1609+ //
1610+ // Stop on first failure and propagate. The caller is
1611+ // responsible for invoking this function again with
1612+ // IsCreated=FALSE to roll back any port bits already
1613+ // set on previous interfaces.
1614+ //
1615+ break ;
1616+ }
15771617 }
15781618 } else {
15791619 //
@@ -1588,6 +1628,8 @@ CxPlatDpRawPlumbRulesOnSocket(
15881628 }
15891629 }
15901630 }
1631+
1632+ return Status ;
15911633}
15921634
15931635_IRQL_requires_max_ (DISPATCH_LEVEL )
0 commit comments