//============================================================================ // Copyright (c) 1995, Microsoft Corporation // // File: timer.c // // History: // V Raman June-25-1997 Created. // // Functions to manager ageing out of MFEs. //============================================================================ #include "pchmgm.h" #pragma hdrstop //---------------------------------------------------------------------------- // DeleteFromForwarder // // This function is an entry point for IP RouterManager. It is invoked // in response to deletion (because of timeouts) of MFEs in the kernel // mode forwarder. This entry point is invoked with a list of deleted // MFEs. // // This function flags each of the MFEs that have been deleted by the // forwarder as "not present in the forwarder" //---------------------------------------------------------------------------- DWORD DeleteFromForwarder( DWORD dwEntryCount, PIPMCAST_DELETE_MFE pimdmMfes ) { DWORD dwInd, dwGrpBucket, dwSrcBucket; PGROUP_ENTRY pge; PSOURCE_ENTRY pse; PLIST_ENTRY pleHead; TRACE1( TIMER, "ENTERED DeleteFromForwarder, Entries %x", dwEntryCount ); // // for each MFE that has been deleted from the KMF // for ( dwInd = 0; dwInd < dwEntryCount; dwInd++ ) { // // 1. Lookup the MFE in MGM // // // 1.1 Find group entry // dwGrpBucket = GROUP_TABLE_HASH( pimdmMfes[ dwInd ].dwGroup, 0 ); ACQUIRE_GROUP_LOCK_SHARED( dwGrpBucket ); pleHead = GROUP_BUCKET_HEAD( dwGrpBucket ); pge = GetGroupEntry( pleHead, pimdmMfes[ dwInd ].dwGroup, 0 ); if ( pge != NULL ) { // // 1.2 Group entry found, find source entry // ACQUIRE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge ); dwSrcBucket = SOURCE_TABLE_HASH( pimdmMfes[ dwInd ].dwSource, pimdmMfes[ dwInd ].dwSrcMask ); pleHead = SOURCE_BUCKET_HEAD( pge, dwSrcBucket ); pse = GetSourceEntry( pleHead, pimdmMfes[ dwInd ].dwSource, pimdmMfes[ dwInd ].dwSrcMask ); if ( pse != NULL ) { pse-> bInForwarder = FALSE; } else { TRACE2( TIMER, "DeleteFromForwarder - Source Entry not found : " "( %x, %x )", pimdmMfes[ dwInd ].dwSource, pimdmMfes[ dwInd ].dwSrcMask ); } RELEASE_GROUP_ENTRY_LOCK_EXCLUSIVE( pge ); } else { TRACE1( TIMER, "DeleteFromForwarder - Group Entry not found : " "( %x )", pimdmMfes[ dwInd ].dwGroup ); } RELEASE_GROUP_LOCK_SHARED( dwGrpBucket ); } TRACE0( TIMER, "LEAVING DeleteFromForwarder\n" ); return NO_ERROR; } //---------------------------------------------------------------------------- // MFETimerProc // // This function is invoked by the MFE timer mechanism. // It deletes the MFE that has timed out from the source/group table. // If the MFE is currently present in the Kernel mode forwarder, then // it is deleted from the forwarder as well. // // If this MFE was in use by the forwarder, it will be recreated on the // next packet miss. // //---------------------------------------------------------------------------- VOID MFETimerProc( PVOID pvContext, BOOLEAN pbFlag ) { BOOL bUnLock = FALSE, bUnMark = FALSE; DWORD dwIfBucket, dwErr; PLIST_ENTRY pleIfHead; PIF_ENTRY pie = NULL; PIF_REFERENCE_ENTRY pire = NULL; PTIMER_CONTEXT ptwc = (PTIMER_CONTEXT) pvContext; RTM_NET_ADDRESS rnaSource; RTM_DEST_INFO rdiDestInfo; PBYTE pbOpaqueInfo = NULL; PMGM_LOCKED_LIST pmllMfeList; PROUTE_REFERENCE_ENTRY prreNew = NULL; TRACE4( TIMER, "ENTERED MFETimerProc, Source : %x %x, Group : %x %x", ptwc-> dwSourceAddr, ptwc-> dwSourceMask, ptwc-> dwGroupAddr, ptwc-> dwGroupMask ); do { // // delete the reference to this MFE in the route used for its RPF // do { // // Lookup route to source // RTM_IPV4_MAKE_NET_ADDRESS( &rnaSource, ptwc-> dwSourceAddr, IPv4_ADDR_LEN ); dwErr = RtmGetMostSpecificDestination( g_hRtmHandle, &rnaSource, RTM_BEST_PROTOCOL, RTM_VIEW_MASK_MCAST, &rdiDestInfo ); if ( dwErr != NO_ERROR ) { TRACE2( ANY, "No Route to source %x, %d", ptwc-> dwSourceAddr, dwErr ); break; } // // Lock the dest // dwErr = RtmLockDestination( g_hRtmHandle, rdiDestInfo.DestHandle, TRUE, TRUE ); if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to lock dest %x", dwErr ); break; } bUnLock = TRUE; // // Get the opaque pointer // dwErr = RtmGetOpaqueInformationPointer( g_hRtmHandle, rdiDestInfo.DestHandle, &pbOpaqueInfo ); if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to retrieve opaque pointer %x", dwErr ); break; } // // if opaque info is present // if ( *( ( PBYTE * ) pbOpaqueInfo ) != NULL ) { pmllMfeList = ( PMGM_LOCKED_LIST ) *( ( PBYTE *) pbOpaqueInfo ); ACQUIRE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList ); // // delete the rre from the list // if ( FindRouteRefEntry( &pmllMfeList-> leHead, ptwc-> dwSourceAddr, ptwc-> dwSourceMask, ptwc-> dwGroupAddr, ptwc-> dwGroupMask, &prreNew ) ) { DeleteRouteRef( prreNew ); } else { TRACE1( ANY, "Reference does not exist for source %x", ptwc-> dwSourceAddr ); } // // if there are no more references to this dest, delete the locked list // if ( IsListEmpty( &pmllMfeList-> leHead ) ) { // // Clear opaque pointer info // *( ( PBYTE * ) pbOpaqueInfo ) = NULL; // // release list lock // RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList ); MGM_FREE( pmllMfeList ); // // unmark the dest. Change notifications for this // dest are no longer required. // bUnMark = TRUE; } else { // // release the list lock // RELEASE_ROUTE_LOCK_EXCLUSIVE( pmllMfeList ); } dwErr = NO_ERROR; } } while ( FALSE ); // // Unlock dest // if ( bUnLock ) { dwErr = RtmLockDestination( g_hRtmHandle, rdiDestInfo.DestHandle, TRUE, FALSE ); if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to unlock dest : %x", dwErr ); } } // // Unmark dest // if ( bUnMark ) { dwErr = RtmMarkDestForChangeNotification( g_hRtmHandle, g_hNotificationHandle, rdiDestInfo.DestHandle, FALSE ); if ( dwErr != NO_ERROR ) { TRACE1( ANY, "Failed to unmark DEST: %x", dwErr ); } } // // delete the MFE and the reference to it in the // incoming interface entry // // // find If entry for incomng interface of the MFE // dwIfBucket = IF_TABLE_HASH( ptwc-> dwIfIndex ); ACQUIRE_IF_LOCK_EXCLUSIVE( dwIfBucket ); pleIfHead = IF_BUCKET_HEAD( dwIfBucket ); if ( !FindIfEntry( pleIfHead, ptwc-> dwIfIndex, ptwc-> dwIfNextHopAddr, &pie ) ) { // // specified incoming interface does not exist, // this is an error condition. All MFEs using this // interface should have been deleted when this interface // was removed. print an error message and quit. // TRACE2( ANY, "MFETimerProc has invalid incoming interface : %x, %x", ptwc-> dwIfIndex, ptwc-> dwIfNextHopAddr ); TRACE4( ANY, "Source : %x %x, Group : %x %x", ptwc-> dwSourceAddr, ptwc-> dwSourceMask, ptwc-> dwGroupAddr, ptwc-> dwGroupMask ); break; } LookupAndDeleteYourMfe( ptwc-> dwSourceAddr, ptwc-> dwSourceMask, ptwc-> dwGroupAddr, ptwc-> dwGroupMask, TRUE, NULL, NULL ); // // delete reference to this MFE from the incoming refeence list // for this interface // pleIfHead = &pie-> leInIfList; if ( !FindRefEntry( pleIfHead, ptwc-> dwSourceAddr, ptwc-> dwSourceMask, ptwc-> dwGroupAddr, ptwc-> dwGroupMask, &pire ) ) { // // Apparently this interface is not reference by the specified // MFE. This is a non-critical error. Log a message too track // this condition. // TRACE2( ANY, "MFETimerProc : No reference for interface : %x, %x", ptwc-> dwIfIndex, ptwc-> dwIfNextHopAddr ); TRACE4( ANY, "Source : %x %x, Group : %x %x", ptwc-> dwSourceAddr, ptwc-> dwSourceMask, ptwc-> dwGroupAddr, ptwc-> dwGroupMask ); break; } RemoveEntryList( &pire-> leRefList ); MGM_FREE( pire ); } while ( FALSE ); RELEASE_IF_LOCK_EXCLUSIVE( dwIfBucket ); // // release route reference. // MGM_FREE( ptwc ); TRACE0( TIMER, "LEAVING MFETimerProc\n" ); }