/* * -------------------------------------------------------------------------- * This function allocated the switch context, and initializes its necessary * members. * -------------------------------------------------------------------------- */ NDIS_STATUS OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle, POVS_SWITCH_CONTEXT *switchContextOut) { NDIS_STATUS status; POVS_SWITCH_CONTEXT switchContext; NDIS_SWITCH_CONTEXT hostSwitchContext; NDIS_SWITCH_OPTIONAL_HANDLERS hostSwitchHandler; OVS_LOG_TRACE("Enter: Create switch object"); switchContext = (POVS_SWITCH_CONTEXT) OvsAllocateMemoryWithTag( sizeof(OVS_SWITCH_CONTEXT), OVS_SWITCH_POOL_TAG); if (switchContext == NULL) { status = NDIS_STATUS_RESOURCES; goto create_switch_done; } RtlZeroMemory(switchContext, sizeof(OVS_SWITCH_CONTEXT)); /* Initialize the switch. */ hostSwitchHandler.Header.Type = NDIS_OBJECT_TYPE_SWITCH_OPTIONAL_HANDLERS; hostSwitchHandler.Header.Size = NDIS_SIZEOF_SWITCH_OPTIONAL_HANDLERS_REVISION_1; hostSwitchHandler.Header.Revision = NDIS_SWITCH_OPTIONAL_HANDLERS_REVISION_1; status = NdisFGetOptionalSwitchHandlers(ndisFilterHandle, &hostSwitchContext, &hostSwitchHandler); if (status != NDIS_STATUS_SUCCESS) { OVS_LOG_ERROR("OvsExtAttach: Extension is running in " "non-switch environment."); OvsFreeMemoryWithTag(switchContext, OVS_SWITCH_POOL_TAG); goto create_switch_done; } switchContext->NdisFilterHandle = ndisFilterHandle; switchContext->NdisSwitchContext = hostSwitchContext; RtlCopyMemory(&switchContext->NdisSwitchHandlers, &hostSwitchHandler, sizeof(NDIS_SWITCH_OPTIONAL_HANDLERS)); status = OvsInitSwitchContext(switchContext); if (status != NDIS_STATUS_SUCCESS) { OvsFreeMemoryWithTag(switchContext, OVS_SWITCH_POOL_TAG); switchContext = NULL; goto create_switch_done; } status = OvsInitTunnelFilter(gOvsExtDriverObject, gOvsDeviceObject); if (status != NDIS_STATUS_SUCCESS) { OvsUninitSwitchContext(switchContext); goto create_switch_done; } *switchContextOut = switchContext; create_switch_done: OVS_LOG_TRACE("Exit: switchContext: %p status: %#lx", switchContext, status); return status; }
/* * -------------------------------------------------------------------------- * Utility function to get the array of nics on the extensible switch. Upon * success, the caller needs to free the returned array. * -------------------------------------------------------------------------- */ NDIS_STATUS OvsGetNicsOnSwitch(POVS_SWITCH_CONTEXT switchContext, PNDIS_SWITCH_NIC_ARRAY *nicArrayOut) { PNDIS_SWITCH_NIC_ARRAY nicArray; UINT32 arraySize = sizeof *nicArray; NDIS_STATUS status = NDIS_STATUS_FAILURE; OVS_LOG_TRACE("Enter: switchContext: %p, nicArray: %p", switchContext, nicArrayOut); do { UINT32 reqdArraySize; nicArray = OvsAllocateMemoryWithTag(arraySize, OVS_OID_POOL_TAG); if (!nicArray) { status = NDIS_STATUS_RESOURCES; goto done; } /* * Even though 'nicArray' is supposed to be populated by the OID, it * needs to be initialized nevertheless. Otherwise, OID returns * NDIS_STATUS_INVALID_PARAMETER. This is not clear in the documentation. */ RtlZeroMemory(nicArray, sizeof *nicArray); nicArray->Header.Revision = NDIS_SWITCH_NIC_ARRAY_REVISION_1; nicArray->Header.Type = NDIS_OBJECT_TYPE_DEFAULT; nicArray->Header.Size = NDIS_SIZEOF_NDIS_SWITCH_NIC_ARRAY_REVISION_1; status = OvsIssueOidRequest(switchContext, NdisRequestQueryInformation, OID_SWITCH_NIC_ARRAY, NULL, 0, (PVOID)nicArray, arraySize, &reqdArraySize); if (status == NDIS_STATUS_SUCCESS) { *nicArrayOut = nicArray; break; } OvsFreeMemoryWithTag(nicArray, OVS_OID_POOL_TAG); arraySize = reqdArraySize; if (status != NDIS_STATUS_INVALID_LENGTH) { break; } } while(status == NDIS_STATUS_INVALID_LENGTH); done: OVS_LOG_TRACE("Exit: status %8x.", status); return status; }
/* * -------------------------------------------------------------------------- * Utility function to query if the extensible switch has completed activation * successfully. * -------------------------------------------------------------------------- */ NDIS_STATUS OvsQuerySwitchActivationComplete(POVS_SWITCH_CONTEXT switchContext, BOOLEAN *switchActive) { NDIS_STATUS status; PNDIS_SWITCH_PARAMETERS switchParams; UINT32 outputSizeNeeded; OVS_LOG_TRACE("Enter: switchContext: %p, switchActive: %p", switchContext, switchActive); switchParams = OvsAllocateMemoryWithTag(sizeof *switchParams, OVS_OID_POOL_TAG); if (!switchParams) { status = NDIS_STATUS_RESOURCES; goto done; } /* * Even though 'switchParms' is supposed to be populated by the OID, it * needs to be initialized nevertheless. Otherwise, OID returns * NDIS_STATUS_INVALID_PARAMETER. This is not clear in the documentation. */ RtlZeroMemory(switchParams, sizeof *switchParams); switchParams->Header.Revision = NDIS_SWITCH_PARAMETERS_REVISION_1; switchParams->Header.Type = NDIS_OBJECT_TYPE_DEFAULT; switchParams->Header.Size = NDIS_SIZEOF_NDIS_SWITCH_PARAMETERS_REVISION_1; status = OvsIssueOidRequest(switchContext, NdisRequestQueryInformation, OID_SWITCH_PARAMETERS, NULL, 0, (PVOID)switchParams, sizeof *switchParams, &outputSizeNeeded); ASSERT(status != NDIS_STATUS_INVALID_LENGTH); ASSERT(status != NDIS_STATUS_PENDING); if (status == NDIS_STATUS_SUCCESS) { ASSERT(switchParams->Header.Type == NDIS_OBJECT_TYPE_DEFAULT); ASSERT(switchParams->Header.Revision == NDIS_SWITCH_PARAMETERS_REVISION_1); ASSERT(switchParams->Header.Size == NDIS_SIZEOF_NDIS_SWITCH_PARAMETERS_REVISION_1); *switchActive = switchParams->IsActive; } OvsFreeMemoryWithTag(switchParams, OVS_OID_POOL_TAG); done: OVS_LOG_TRACE("Exit: status %8x, switchActive: %d.", status, *switchActive); return status; }
VOID * OvsAllocateMemoryPerCpu(size_t size, ULONG tag) { VOID *ptr = NULL; ULONG count = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS); ASSERT(KeQueryActiveGroupCount() == 1); ptr = OvsAllocateMemoryWithTag(count * size, tag); if (ptr) { RtlZeroMemory(ptr, count * size); } return ptr; }
OVS_CT_ENTRY * OvsConntrackCreateTcpEntry(const TCPHdr *tcp, PNET_BUFFER_LIST nbl, UINT64 now) { struct conn_tcp* newconn; struct tcp_peer *src, *dst; newconn = OvsAllocateMemoryWithTag(sizeof(struct conn_tcp), OVS_CT_POOL_TAG); if (!newconn) { return NULL; } newconn->up = (OVS_CT_ENTRY) {0}; src = &newconn->peer[0]; dst = &newconn->peer[1]; src->seqlo = ntohl(tcp->seq); src->seqhi = src->seqlo + OvsGetTcpPayloadLength(nbl) + 1; if (tcp->flags & TCP_SYN) { src->seqhi++; src->wscale = OvsTcpGetWscale(tcp); } else { src->wscale = CT_WSCALE_UNKNOWN; dst->wscale = CT_WSCALE_UNKNOWN; } src->max_win = MAX(ntohs(tcp->window), 1); if (src->wscale & CT_WSCALE_MASK) { /* Remove scale factor from initial window */ uint8_t sws = src->wscale & CT_WSCALE_MASK; src->max_win = DIV_ROUND_UP((uint32_t) src->max_win, 1 << sws); } if (tcp->flags & TCP_FIN) { src->seqhi++; } dst->seqhi = 1; dst->max_win = 1; src->state = CT_DPIF_TCPS_SYN_SENT; dst->state = CT_DPIF_TCPS_CLOSED; OvsConntrackUpdateExpiration(newconn, now, CT_ENTRY_TIMEOUT); return &newconn->up; }
static PMDL OvsAllocateMDLAndData(NDIS_HANDLE ndisHandle, UINT32 dataSize) { PMDL mdl; PVOID data; data = OvsAllocateMemoryWithTag(dataSize, OVS_MDL_POOL_TAG); if (data == NULL) { return NULL; } mdl = NdisAllocateMdl(ndisHandle, data, dataSize); if (mdl == NULL) { OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG); } return mdl; }
static NDIS_STATUS OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext) { int i; NTSTATUS status; OVS_LOG_TRACE("Enter: switchContext: %p", switchContext); switchContext->dispatchLock = NdisAllocateRWLock(switchContext->NdisFilterHandle); switchContext->portNoHashArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag( sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG); switchContext->ovsPortNameHashArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag( sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG); switchContext->portIdHashArray= (PLIST_ENTRY)OvsAllocateMemoryWithTag( sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG); switchContext->pidHashArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag( sizeof(LIST_ENTRY) * OVS_MAX_PID_ARRAY_SIZE, OVS_SWITCH_POOL_TAG); status = OvsAllocateFlowTable(&switchContext->datapath, switchContext); if (status == NDIS_STATUS_SUCCESS) { status = OvsInitBufferPool(switchContext); } if (status != NDIS_STATUS_SUCCESS || switchContext->dispatchLock == NULL || switchContext->portNoHashArray == NULL || switchContext->ovsPortNameHashArray == NULL || switchContext->portIdHashArray== NULL || switchContext->pidHashArray == NULL) { if (switchContext->dispatchLock) { NdisFreeRWLock(switchContext->dispatchLock); } if (switchContext->portNoHashArray) { OvsFreeMemoryWithTag(switchContext->portNoHashArray, OVS_SWITCH_POOL_TAG); } if (switchContext->ovsPortNameHashArray) { OvsFreeMemoryWithTag(switchContext->ovsPortNameHashArray, OVS_SWITCH_POOL_TAG); } if (switchContext->portIdHashArray) { OvsFreeMemoryWithTag(switchContext->portIdHashArray, OVS_SWITCH_POOL_TAG); } if (switchContext->pidHashArray) { OvsFreeMemoryWithTag(switchContext->pidHashArray, OVS_SWITCH_POOL_TAG); } OvsDeleteFlowTable(&switchContext->datapath); OvsCleanupBufferPool(switchContext); OVS_LOG_TRACE("Exit: Failed to init switchContext"); return NDIS_STATUS_RESOURCES; } for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) { InitializeListHead(&switchContext->ovsPortNameHashArray[i]); } for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) { InitializeListHead(&switchContext->portIdHashArray[i]); } for (i = 0; i < OVS_MAX_VPORT_ARRAY_SIZE; i++) { InitializeListHead(&switchContext->portNoHashArray[i]); } for (i = 0; i < OVS_MAX_PID_ARRAY_SIZE; i++) { InitializeListHead(&switchContext->pidHashArray[i]); } NdisAllocateSpinLock(&(switchContext->pidHashLock)); switchContext->isActivated = FALSE; switchContext->isActivateFailed = FALSE; switchContext->dpNo = OVS_DP_NUMBER; ovsTimeIncrementPerTick = KeQueryTimeIncrement() / 10000; OVS_LOG_TRACE("Exit: Succesfully initialized switchContext: %p", switchContext); return NDIS_STATUS_SUCCESS; }
/* * -------------------------------------------------------------------------- * Utility function to issue the specified OID to the NDIS stack. The OID is * directed towards the miniport edge of the extensible switch. * An OID that gets issued may not complete immediately, and in such cases, the * function waits for the OID to complete. Thus, this function must not be * called at the PASSIVE_LEVEL. * -------------------------------------------------------------------------- */ static NDIS_STATUS OvsIssueOidRequest(POVS_SWITCH_CONTEXT switchContext, NDIS_REQUEST_TYPE oidType, UINT32 oidRequestEnum, PVOID oidInputBuffer, UINT32 inputSize, PVOID oidOutputBuffer, UINT32 outputSize, UINT32 *outputSizeNeeded) { NDIS_STATUS status; PNDIS_OID_REQUEST oidRequest; POVS_OID_CONTEXT oidContext; ULONG OvsExtOidRequestId = 'ISVO'; DBG_UNREFERENCED_PARAMETER(inputSize); DBG_UNREFERENCED_PARAMETER(oidInputBuffer); OVS_LOG_TRACE("Enter: switchContext: %p, oidType: %d", switchContext, oidType); ASSERT(oidInputBuffer == NULL || inputSize != 0); ASSERT(oidOutputBuffer == NULL || outputSize != 0); ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); oidRequest = OvsAllocateMemoryWithTag(sizeof *oidRequest, OVS_OID_POOL_TAG); if (!oidRequest) { status = NDIS_STATUS_RESOURCES; goto done; } oidContext = OvsAllocateMemoryWithTag(sizeof *oidContext, OVS_OID_POOL_TAG); if (!oidContext) { OvsFreeMemoryWithTag(oidRequest, OVS_OID_POOL_TAG); status = NDIS_STATUS_RESOURCES; goto done; } RtlZeroMemory(oidRequest, sizeof *oidRequest); RtlZeroMemory(oidContext, sizeof *oidContext); oidRequest->Header.Type = NDIS_OBJECT_TYPE_OID_REQUEST; oidRequest->Header.Revision = NDIS_OID_REQUEST_REVISION_1; oidRequest->Header.Size = NDIS_SIZEOF_OID_REQUEST_REVISION_1; oidRequest->RequestType = oidType; oidRequest->PortNumber = 0; oidRequest->Timeout = 0; oidRequest->RequestId = (PVOID)OvsExtOidRequestId; switch(oidType) { case NdisRequestQueryInformation: oidRequest->DATA.QUERY_INFORMATION.Oid = oidRequestEnum; oidRequest->DATA.QUERY_INFORMATION.InformationBuffer = oidOutputBuffer; oidRequest->DATA.QUERY_INFORMATION.InformationBufferLength = outputSize; break; default: ASSERT(FALSE); status = NDIS_STATUS_INVALID_PARAMETER; break; } /* * We make use of the SourceReserved field in the OID request to store * pointers to the original OID (if any), and also context for completion * (if any). */ oidContext->status = NDIS_STATUS_SUCCESS; NdisInitializeEvent(&oidContext->oidComplete); OvsOidSetOrigRequest(oidRequest, NULL); OvsOidSetContext(oidRequest, oidContext); NdisInterlockedIncrement(&(switchContext->pendingOidCount)); status = NdisFOidRequest(switchContext->NdisFilterHandle, oidRequest); if (status == NDIS_STATUS_PENDING) { NdisWaitEvent(&oidContext->oidComplete, 0); } else { NdisInterlockedDecrement(&(switchContext->pendingOidCount)); } if (status == NDIS_STATUS_INVALID_LENGTH || oidContext->status == NDIS_STATUS_INVALID_LENGTH) { switch(oidType) { case NdisRequestQueryInformation: *outputSizeNeeded = oidRequest->DATA.QUERY_INFORMATION.BytesNeeded; } } status = oidContext->status; ASSERT(status != NDIS_STATUS_PENDING); OvsFreeMemoryWithTag(oidRequest, OVS_OID_POOL_TAG); OvsFreeMemoryWithTag(oidContext, OVS_OID_POOL_TAG); done: OVS_LOG_TRACE("Exit: status %8x.", status); return status; }