datapath-windows/ovsext/IpHelper.c
/*
 *----------------------------------------------------------------------------
 *  IP Helper system thread handles the following requests:
 *    1. Intialize Internal port row when internal port is connected
 *    2. Handle FWD request
 *    3. Handle IP Neigh timeout
 *
 *    IP Interface, unicast address, and IP route change will be handled
 *    by the revelant callbacks.
 *----------------------------------------------------------------------------
 */
IP Helper system thread handles the following requests:
1. Intialize Internal port row when internal port is connected
2. Handle FWD request
3. Handle IP Neigh timeout

IP Interface, unicast address, and IP route change will be handled
by the revelant callbacks.
IP Helper system thread handles the following requests : 1 . Intialize Internal port row when internal port is connected 2 . Handle FWD request 3 . Handle IP Neigh timeout IP Interface unicast address and IP route change will be handled by the revelant callbacks .
VOID
OvsStartIpHelper(PVOID data)
{
    POVS_IP_HELPER_THREAD_CONTEXT context = (POVS_IP_HELPER_THREAD_CONTEXT)data;
    POVS_IP_HELPER_REQUEST req;
    POVS_IPNEIGH_ENTRY ipn;
    PLIST_ENTRY link;
    UINT64   timeVal, timeout;
    PLARGE_INTEGER threadSleepTimeout;
    OVS_LOG_INFO("Start the IP Helper Thread, context: %p", context);
    NdisAcquireSpinLock(&ovsIpHelperLock);
    while (!context->exit) {
        threadSleepTimeout = NULL;
        timeout = 0;
        while (!IsListEmpty(&ovsIpHelperRequestList)) {
            if (context->exit) {
                goto ip_helper_wait;
            }
            link = ovsIpHelperRequestList.Flink;
            RemoveEntryList(link);
            ovsNumIpHelperRequests--;
            NdisReleaseSpinLock(&ovsIpHelperLock);
            req = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
            switch (req->command) {
            case OVS_IP_HELPER_INTERNAL_ADAPTER_UP:
                OvsHandleInternalAdapterUp(req);
                break;
            case OVS_IP_HELPER_INTERNAL_ADAPTER_DOWN:
            {
                PLIST_ENTRY head, current, next;
                UINT32 portNo = req->instanceReq.portNo;
                GUID netCfgInstanceId = req->instanceReq.netCfgInstanceId;
                ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
                head = &ovsInstanceList;
                LIST_FORALL_SAFE(head, current, next) {
                    POVS_IPHELPER_INSTANCE instance = NULL;
                    LOCK_STATE_EX lockState;
                    instance = CONTAINING_RECORD(current, OVS_IPHELPER_INSTANCE,
                                                 link);
                    ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
                    if (instance->portNo == portNo &&
                        IsEqualGUID(&instance->netCfgId, &netCfgInstanceId)) {
                        NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
                        OvsRemoveIPNeighEntriesWithInstance(instance);
                        NdisReleaseRWLock(ovsTableLock, &lockState);
                        RemoveEntryList(&instance->link);
                        ExReleaseResourceLite(&instance->lock);
                        OvsIpHelperDeleteInstance(instance);
                        break;
                    }
                    ExReleaseResourceLite(&instance->lock);
                }
                if (IsListEmpty(&ovsInstanceList)) {
                    OvsCleanupIpHelperRequestList();
                    OvsCleanupFwdTable();
                }
                ExReleaseResourceLite(&ovsInstanceListLock);
            }
            case OVS_IP_HELPER_FWD_REQUEST:
                OvsHandleFwdRequest(req);
                break;
            default:
                OvsFreeMemoryWithTag(req, OVS_IPHELPER_POOL_TAG);
            }
            NdisAcquireSpinLock(&ovsIpHelperLock);
        }
        while (!IsListEmpty(&ovsSortedIPNeighList)) {
            UINT32 ipAddr;
            if (context->exit) {
                goto ip_helper_wait;
            }
            link = ovsSortedIPNeighList.Flink;
            ipn = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);
            KeQuerySystemTime((LARGE_INTEGER *)&timeVal);
            if (ipn->timeout > timeVal) {
                timeout = ipn->timeout;
                threadSleepTimeout = (PLARGE_INTEGER)&timeout;
                break;
            }
            ipAddr = ipn->ipAddr;
            MIB_IPNET_ROW2 ipNeigh;
            NTSTATUS status;
            POVS_IPHELPER_INSTANCE instance = ipn->instance;
            NdisReleaseSpinLock(&ovsIpHelperLock);
            if (instance) {
                ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
                status = OvsGetOrResolveIPNeigh(&instance->internalRow,
                                                ipAddr, &ipNeigh);
                OvsUpdateIPNeighEntry(ipAddr, &ipNeigh, status);
                ExReleaseResourceLite(&instance->lock);
            }
            NdisAcquireSpinLock(&ovsIpHelperLock);
        }
        if (!IsListEmpty(&ovsIpHelperRequestList)) {
            continue;
        }
ip_helper_wait:
        if (context->exit) {
            break;
        }
        KeClearEvent(&context->event);
        NdisReleaseSpinLock(&ovsIpHelperLock);
        KeWaitForSingleObject(&context->event, Executive, KernelMode,
                              FALSE, threadSleepTimeout);
        NdisAcquireSpinLock(&ovsIpHelperLock);
    }
    NdisReleaseSpinLock(&ovsIpHelperLock);
    OvsCleanupFwdTable();
    OvsCleanupIpHelperRequestList();
    OVS_LOG_INFO("Terminating the OVS IP Helper system thread");
    PsTerminateSystemThread(STATUS_SUCCESS);
}
VOID OvsStartIpHelper ( PVOID data ) { POVS_IP_HELPER_THREAD_CONTEXT context = ( POVS_IP_HELPER_THREAD_CONTEXT ) data ; POVS_IP_HELPER_REQUEST req ; POVS_IPNEIGH_ENTRY ipn ; PLIST_ENTRY link ; UINT64 timeVal , timeout ; PLARGE_INTEGER threadSleepTimeout ; OVS_LOG_INFO ( " " , context ) ; NdisAcquireSpinLock ( & ovsIpHelperLock ) ; while ( ! context -> exit ) { threadSleepTimeout = NULL ; timeout = 0 ; while ( ! IsListEmpty ( & ovsIpHelperRequestList ) ) { if ( context -> exit ) { goto ip_helper_wait ; } link = ovsIpHelperRequestList . Flink ; RemoveEntryList ( link ) ; ovsNumIpHelperRequests -- ; NdisReleaseSpinLock ( & ovsIpHelperLock ) ; req = CONTAINING_RECORD ( link , OVS_IP_HELPER_REQUEST , link ) ; switch ( req -> command ) { case OVS_IP_HELPER_INTERNAL_ADAPTER_UP : OvsHandleInternalAdapterUp ( req ) ; break ; case OVS_IP_HELPER_INTERNAL_ADAPTER_DOWN : { PLIST_ENTRY head , current , next ; UINT32 portNo = req -> instanceReq . portNo ; GUID netCfgInstanceId = req -> instanceReq . netCfgInstanceId ; ExAcquireResourceExclusiveLite ( & ovsInstanceListLock , TRUE ) ; head = & ovsInstanceList ; LIST_FORALL_SAFE ( head , current , next ) { POVS_IPHELPER_INSTANCE instance = NULL ; LOCK_STATE_EX lockState ; instance = CONTAINING_RECORD ( current , OVS_IPHELPER_INSTANCE , link ) ; ExAcquireResourceExclusiveLite ( & instance -> lock , TRUE ) ; if ( instance -> portNo == portNo && IsEqualGUID ( & instance -> netCfgId , & netCfgInstanceId ) ) { NdisAcquireRWLockWrite ( ovsTableLock , & lockState , 0 ) ; OvsRemoveIPNeighEntriesWithInstance ( instance ) ; NdisReleaseRWLock ( ovsTableLock , & lockState ) ; RemoveEntryList ( & instance -> link ) ; ExReleaseResourceLite ( & instance -> lock ) ; OvsIpHelperDeleteInstance ( instance ) ; break ; } ExReleaseResourceLite ( & instance -> lock ) ; } if ( IsListEmpty ( & ovsInstanceList ) ) { OvsCleanupIpHelperRequestList ( ) ; OvsCleanupFwdTable ( ) ; } ExReleaseResourceLite ( & ovsInstanceListLock ) ; } case OVS_IP_HELPER_FWD_REQUEST : OvsHandleFwdRequest ( req ) ; break ; default : OvsFreeMemoryWithTag ( req , OVS_IPHELPER_POOL_TAG ) ; } NdisAcquireSpinLock ( & ovsIpHelperLock ) ; } while ( ! IsListEmpty ( & ovsSortedIPNeighList ) ) { UINT32 ipAddr ; if ( context -> exit ) { goto ip_helper_wait ; } link = ovsSortedIPNeighList . Flink ; ipn = CONTAINING_RECORD ( link , OVS_IPNEIGH_ENTRY , slink ) ; KeQuerySystemTime ( ( LARGE_INTEGER * ) & timeVal ) ; if ( ipn -> timeout > timeVal ) { timeout = ipn -> timeout ; threadSleepTimeout = ( PLARGE_INTEGER ) & timeout ; break ; } ipAddr = ipn -> ipAddr ; MIB_IPNET_ROW2 ipNeigh ; NTSTATUS status ; POVS_IPHELPER_INSTANCE instance = ipn -> instance ; NdisReleaseSpinLock ( & ovsIpHelperLock ) ; if ( instance ) { ExAcquireResourceExclusiveLite ( & instance -> lock , TRUE ) ; status = OvsGetOrResolveIPNeigh ( & instance -> internalRow , ipAddr , & ipNeigh ) ; OvsUpdateIPNeighEntry ( ipAddr , & ipNeigh , status ) ; ExReleaseResourceLite ( & instance -> lock ) ; } NdisAcquireSpinLock ( & ovsIpHelperLock ) ; } if ( ! IsListEmpty ( & ovsIpHelperRequestList ) ) { continue ; } ip_helper_wait : if ( context -> exit ) { break ; } KeClearEvent ( & context -> event ) ; NdisReleaseSpinLock ( & ovsIpHelperLock ) ; KeWaitForSingleObject ( & context -> event , Executive , KernelMode , FALSE , threadSleepTimeout ) ; NdisAcquireSpinLock ( & ovsIpHelperLock ) ; } NdisReleaseSpinLock ( & ovsIpHelperLock ) ; OvsCleanupFwdTable ( ) ; OvsCleanupIpHelperRequestList ( ) ; OVS_LOG_INFO ( " " ) ; PsTerminateSystemThread ( STATUS_SUCCESS ) ; }
IP Helper system thread handles the following requests:
    1.
IP Helper system thread handles the following requests : 1 .
/* for now, let us hold the lock here, if this cause any issue
         * we will change to use IpHelper lock only to protect
         * IPN
         */ /*
         * Wait indefinitely for the thread to be woken up.
         * Passing NULL as the Timeout value in the below
         * call to KeWaitForSingleObject achieves this.
         */