diff --git a/.azure/OneBranch.Official.yml b/.azure/OneBranch.Official.yml index 9f023aaa2d..520dfcf7f8 100644 --- a/.azure/OneBranch.Official.yml +++ b/.azure/OneBranch.Official.yml @@ -78,10 +78,10 @@ extends: - container: linux_build_container # Default container image: 'ghcr.io/microsoft/msquic/linux-build-xcomp:ubuntu-20.04-cross' type: Linux - - container: ubuntu_2204_cross + - container: kernel5_15_cross image: 'ghcr.io/microsoft/msquic/linux-build-xcomp:ubuntu-22.04-cross' type: Linux - - container: ubuntu_2404_cross + - container: kernel6_8_cross image: 'ghcr.io/microsoft/msquic/linux-build-xcomp:ubuntu-24.04-cross' type: Linux @@ -179,23 +179,23 @@ extends: - template: .azure/obtemplates/build-linux.yml@self parameters: config: Release - os: ubuntu_2204 + kernel: "kernel5_15" tls: openssl3 - template: .azure/obtemplates/build-linux.yml@self parameters: config: Debug - os: ubuntu_2204 + kernel: "kernel5_15" tls: openssl3 - template: .azure/obtemplates/build-linux.yml@self parameters: config: Release - os: ubuntu_2404 + kernel: "kernel6_8" tls: openssl3 xdp: "-UseXdp" - template: .azure/obtemplates/build-linux.yml@self parameters: config: Debug - os: ubuntu_2404 + kernel: "kernel6_8" tls: openssl3 xdp: "-UseXdp" @@ -207,6 +207,15 @@ extends: - template: .azure/obtemplates/build-linux-packages.yml@self parameters: sign: true + kernel: "kernel5_4" + - template: .azure/obtemplates/build-linux-packages.yml@self + parameters: + sign: true + kernel: "kernel5_15" + - template: .azure/obtemplates/build-linux-packages.yml@self + parameters: + sign: true + kernel: "kernel6_8" - stage: package_windows displayName: Package Windows diff --git a/.azure/OneBranch.Publish.yml b/.azure/OneBranch.Publish.yml index 9df1a6cc88..eae884a1d1 100644 --- a/.azure/OneBranch.Publish.yml +++ b/.azure/OneBranch.Publish.yml @@ -15,308 +15,119 @@ variables: DisableDockerDetector: true parameters: -- name: opensslrpmcblrepos - type: object - default: - - cbl-mariner-1.0-prod-Microsoft-x86_64-rpms-yum - - cbl-mariner-2.0-prod-Microsoft-x86_64-yum - - cbl-mariner-2.0-prod-Microsoft-aarch64-yum -- name: opensslrpmrepos - type: object - default: - - microsoft-sles12-prod-yum - - microsoft-sles15-prod-yum - - microsoft-centos7-prod-yum - - microsoft-centos8-prod-yum - - microsoft-opensuse15-prod-yum - - microsoft-fedora32-prod-yum - - microsoft-fedora33-prod-yum - - microsoft-fedora34-prod-yum - - microsoft-fedora37-prod-yum - - microsoft-rhel7.3-prod-yum - - microsoft-rhel8.0-prod-yum - - microsoft-rhel8.1-prod-yum -- name: openssldebrepos - type: object - default: - - microsoft-debian-stretch-prod-apt - - microsoft-debian-buster-prod-apt - - microsoft-debian-bullseye-prod-apt -- name: openssl3debrepos - type: object - default: - - microsoft-debian-bookworm-prod-apt -- name: openssl3rpmrepos - type: object - default: - - microsoft-fedora36-prod-yum - - microsoft-fedora38-prod-yum - - microsoft-fedora39-prod-yum - - microsoft-rhel9.0-prod-yum - name: debug # debug mode will not actually upload and publish packages type: boolean default: false -- name: ubuntu20repos - type: object - default: - - microsoft-ubuntu-xenial-prod-apt - - microsoft-ubuntu-bionic-prod-apt - - microsoft-ubuntu-focal-prod-apt - - microsoft-ubuntu-groovy-prod-apt - - microsoft-ubuntu-hirsute-prod-apt -- name: ubuntu22repos - type: object - default: - - microsoft-ubuntu-jammy-prod-apt - - microsoft-ubuntu-kinetic-prod-apt - - microsoft-ubuntu-lunar-prod-apt - - microsoft-ubuntu-mantic-prod-apt -- name: ubuntu24repos + +- name: kernel type: object default: - - microsoft-ubuntu-noble-prod-apt + # build on ubuntu 20.04 openssl 1.1 + - name: kernel5_4 + type: object + default: + - name: RPM + destinations: + - microsoft-sles12-prod-yum # 12 3.12 + - microsoft-sles15-prod-yum # 15 4.12 + - microsoft-centos7-prod-yum # 7 3.10 + - microsoft-centos8-prod-yum # 8 4.18 + - microsoft-opensuse15-prod-yum # 15 4.12 + - microsoft-fedora32-prod-yum # 32 5.6 + - microsoft-fedora33-prod-yum # 33 5.8 + - microsoft-fedora34-prod-yum # 34 5.11 + - microsoft-fedora35-prod-yum # 35 5.14 + - microsoft-rhel7.3-prod-yum # 7.3 3.10 + - microsoft-rhel8.0-prod-yum # 8.0 4.18 + - microsoft-rhel8.1-prod-yum # 8.1 4.18 + - name: DEB + destinations: + - microsoft-ubuntu-xenial-prod-apt # 16.04 4.4 + - microsoft-ubuntu-bionic-prod-apt # 18.04 4.15 + - microsoft-ubuntu-focal-prod-apt # 20.04 5.4 + - microsoft-ubuntu-groovy-prod-apt # 20.10 5.8 + - microsoft-ubuntu-hirsute-prod-apt # 21.04 5.11 + - microsoft-debian-stretch-prod-apt # 9 4.9 + - microsoft-debian-buster-prod-apt # 10 4.19 + - microsoft-debian-bullseye-prod-apt # 11 5.10 + - name: CBL + destinations: + - cbl-mariner-1.0-prod-Microsoft-x86_64-rpms-yum + - cbl-mariner-2.0-prod-Microsoft-x86_64-yum + - cbl-mariner-2.0-prod-Microsoft-aarch64-yum + # built on ubuntu 22.04, openssl3 + - name: kernel5_15 + type: object + default: + - name: RPM + destinations: + - microsoft-fedora36-prod-yum # 36 5.17 + - microsoft-fedora37-prod-yum # 37 6.0 + - microsoft-fedora38-prod-yum # 38 6.2 + - microsoft-fedora39-prod-yum # 39 6.5 + - microsoft-rhel9.0-prod-yum # 9.0 5.14 + - name: DEB + destinations: + - microsoft-ubuntu-jammy-prod-apt # 22.04 5.15 + - microsoft-ubuntu-kinetic-prod-apt # 22.10 5.19 + - microsoft-ubuntu-lunar-prod-apt # 23.04 6.2 + - microsoft-ubuntu-mantic-prod-apt # 23.10 6.5 + - microsoft-debian-bookworm-prod-apt # 12 6.1 + # built on ubuntu 24.04 openssl3 XDP + - name: kernel6_8 + type: object + default: + - name: RPM + destionations: + - microsoft-fedora40-prod-yum # 40 6.8 + - name: DEB + destinations: + - microsoft-ubuntu-noble-prod-apt # 24.04 6.8 + - name: CBL + destinations: + - azurelinux-3.0-prod-ms-oss-x86_64-yum # 3.0 6.6 + - azurelinux-3.0-prod-ms-oss-aarch64-yum # 3.0 6.6 stages: - stage: UploadPackage_stage condition: or(startsWith(variables['Build.SourceBranch'], 'refs/tags/'), eq(variables['Build.Reason'], 'Manual')) jobs: - - job: UploadPackage_openssl_debs - displayName: Upload openSSL based DEB packages to repos - timeoutInMinutes: 120 - workspace: - clean: all - pool: - vmImage: 'ubuntu-latest' - variables: - - group: MsQuicAADApp - steps: - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: $(resources.pipeline.onebranch.projectID) - pipeline: $(resources.pipeline.onebranch.pipelineID) - preferTriggeringPipeline: true - runVersion: specific - runId: $(resources.pipeline.onebranch.runID) - artifact: drop_package_linux_distribution_ubuntu_2004_openssl - path: $(Build.SourcesDirectory)/artifacts/signed/openssl - - task: DownloadSecureFile@1 - name: pmcv4cert - displayName: 'Download cert for PMC v4' - inputs: - secureFile: 'auth.pem' - - ${{ each repo in parameters.openssldebrepos }}: - - script: bash scripts/upload-linux-packages.sh -i $(PMCv4ClientId) -c $(pmcv4cert.secureFilePath) -f $(Build.SourcesDirectory)/artifacts/signed/openssl/gen -r ${{ repo }} -n "*.deb" - condition: eq(${{ parameters.debug }}, false) - displayName: ${{ repo }} - continueOnError: true - - job: UploadPackage_openssl_rpms - displayName: Upload openSSL based RPM packages to repos - timeoutInMinutes: 120 - workspace: - clean: all - pool: - vmImage: 'ubuntu-latest' - variables: - - group: MsQuicAADApp - steps: - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: $(resources.pipeline.onebranch.projectID) - pipeline: $(resources.pipeline.onebranch.pipelineID) - preferTriggeringPipeline: true - runVersion: specific - runId: $(resources.pipeline.onebranch.runID) - artifact: drop_package_linux_distribution_ubuntu_2004_openssl - path: $(Build.SourcesDirectory)/artifacts/signed/openssl - - task: DownloadSecureFile@1 - name: pmcv4cert - displayName: 'Download cert for PMC v4' - inputs: - secureFile: 'auth.pem' - - ${{ each repo in parameters.opensslrpmrepos }}: - - script: bash scripts/upload-linux-packages.sh -i $(PMCv4ClientId) -c $(pmcv4cert.secureFilePath) -f $(Build.SourcesDirectory)/artifacts/signed/openssl/gen -r ${{ repo }} -n "*.rpm" - condition: eq(${{ parameters.debug }}, false) - displayName: ${{ repo }} - continueOnError: true - - job: UploadPackage_openssl_rpms_cbl - displayName: Upload openSSL based RPM packages to CBL repos - timeoutInMinutes: 120 - workspace: - clean: all - pool: - vmImage: 'ubuntu-latest' - variables: - - group: MsQuicAADApp - steps: - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: $(resources.pipeline.onebranch.projectID) - pipeline: $(resources.pipeline.onebranch.pipelineID) - preferTriggeringPipeline: true - runVersion: specific - runId: $(resources.pipeline.onebranch.runID) - artifact: drop_package_linux_distribution_ubuntu_2004_openssl - path: $(Build.SourcesDirectory)/artifacts/signed/openssl - - task: DownloadSecureFile@1 - name: pmcv4cert - displayName: 'Download cert for PMC v4' - inputs: - secureFile: 'auth.pem' - - ${{ each repo in parameters.opensslrpmcblrepos }}: - - script: bash scripts/upload-linux-packages.sh -i $(PMCv4ClientId) -c $(pmcv4cert.secureFilePath) -f $(Build.SourcesDirectory)/artifacts/signed/openssl/cbl -r ${{ repo }} -n "*.rpm" - condition: eq(${{ parameters.debug }}, false) - displayName: ${{ repo }} - continueOnError: true - - job: UploadPackage_openssl3_debs - displayName: Upload openSSL3 based DEB packages to repos - timeoutInMinutes: 120 - workspace: - clean: all - pool: - vmImage: 'ubuntu-latest' - variables: - - group: MsQuicAADApp - steps: - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: $(resources.pipeline.onebranch.projectID) - pipeline: $(resources.pipeline.onebranch.pipelineID) - preferTriggeringPipeline: true - runVersion: specific - runId: $(resources.pipeline.onebranch.runID) - artifact: drop_package_linux_distribution_ubuntu_2204_openssl3 - path: $(Build.SourcesDirectory)/artifacts/signed/openssl3 - - task: DownloadSecureFile@1 - name: pmcv4cert - displayName: 'Download cert for PMC v4' - inputs: - secureFile: 'auth.pem' - - ${{ each repo in parameters.openssl3debrepos }}: - - script: bash scripts/upload-linux-packages.sh -i $(PMCv4ClientId) -c $(pmcv4cert.secureFilePath) -f $(Build.SourcesDirectory)/artifacts/signed/openssl3/gen -r ${{ repo }} -n "*.deb" - condition: eq(${{ parameters.debug }}, false) - displayName: ${{ repo }} - continueOnError: true - - job: UploadPackage_ubuntu20 - displayName: Upload Ubuntu 20 packages to repos - timeoutInMinutes: 120 - workspace: - clean: all - pool: - vmImage: 'ubuntu-latest' - variables: - - group: MsQuicAADApp - steps: - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: $(resources.pipeline.onebranch.projectID) - pipeline: $(resources.pipeline.onebranch.pipelineID) - preferTriggeringPipeline: true - runVersion: specific - runId: $(resources.pipeline.onebranch.runID) - artifact: drop_package_linux_distribution_ubuntu_2004_openssl - path: $(Build.SourcesDirectory)/artifacts/signed/ubuntu_2004_openssl - - task: DownloadSecureFile@1 - name: pmcv4cert - displayName: 'Download cert for PMC v4' - inputs: - secureFile: 'auth.pem' - - ${{ each repo in parameters.ubuntu20repos }}: - - script: bash scripts/upload-linux-packages.sh -i $(PMCv4ClientId) -c $(pmcv4cert.secureFilePath) -f $(Build.SourcesDirectory)/artifacts/signed/ubuntu_2004_openssl/gen -r ${{ repo }} -n "*.deb" - condition: eq(${{ parameters.debug }}, false) - displayName: ${{ repo }} - continueOnError: true - - job: UploadPackage_ubuntu22 - displayName: Upload Ubuntu 22 packages to repos - timeoutInMinutes: 120 - workspace: - clean: all - pool: - vmImage: 'ubuntu-latest' - variables: - - group: MsQuicAADApp - steps: - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: $(resources.pipeline.onebranch.projectID) - pipeline: $(resources.pipeline.onebranch.pipelineID) - preferTriggeringPipeline: true - runVersion: specific - runId: $(resources.pipeline.onebranch.runID) - artifact: drop_package_linux_distribution_ubuntu_2204_openssl3 - path: $(Build.SourcesDirectory)/artifacts/signed/ubuntu_2204_openssl3 - - task: DownloadSecureFile@1 - name: pmcv4cert - displayName: 'Download cert for PMC v4' - inputs: - secureFile: 'auth.pem' - - ${{ each repo in parameters.ubuntu22repos }}: - - script: bash scripts/upload-linux-packages.sh -i $(PMCv4ClientId) -c $(pmcv4cert.secureFilePath) -f $(Build.SourcesDirectory)/artifacts/signed/ubuntu_2204_openssl3/gen -r ${{ repo }} -n "*.deb" - condition: eq(${{ parameters.debug }}, false) - displayName: ${{ repo }} - continueOnError: true - - job: UploadPackage_ubuntu24 - displayName: Upload Ubuntu 24 packages to repos - timeoutInMinutes: 120 - workspace: - clean: all - pool: - vmImage: 'ubuntu-latest' - variables: - - group: MsQuicAADApp - steps: - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: $(resources.pipeline.onebranch.projectID) - pipeline: $(resources.pipeline.onebranch.pipelineID) - preferTriggeringPipeline: true - runVersion: specific - runId: $(resources.pipeline.onebranch.runID) - artifact: drop_package_linux_distribution_ubuntu_2404_openssl3 - path: $(Build.SourcesDirectory)/artifacts/signed/ubuntu_2404_openssl3 - - task: DownloadSecureFile@1 - name: pmcv4cert - displayName: 'Download cert for PMC v4' - inputs: - secureFile: 'auth.pem' - - ${{ each repo in parameters.ubuntu24repos }}: - - script: bash scripts/upload-linux-packages.sh -i $(PMCv4ClientId) -c $(pmcv4cert.secureFilePath) -f $(Build.SourcesDirectory)/artifacts/signed/ubuntu_2404_openssl3/gen -r ${{ repo }} -n "*.deb" - condition: eq(${{ parameters.debug }}, false) - displayName: ${{ repo }} - continueOnError: true - - job: UploadPackage_openssl3_rpms - displayName: Upload openSSL3 based RPM packages to repos - timeoutInMinutes: 120 - workspace: - clean: all - pool: - vmImage: 'ubuntu-latest' - variables: - - group: MsQuicAADApp - steps: - - task: DownloadPipelineArtifact@2 - inputs: - source: specific - project: $(resources.pipeline.onebranch.projectID) - pipeline: $(resources.pipeline.onebranch.pipelineID) - preferTriggeringPipeline: true - runVersion: specific - runId: $(resources.pipeline.onebranch.runID) - artifact: drop_package_linux_distribution_ubuntu_2204_openssl3 - path: $(Build.SourcesDirectory)/artifacts/signed/openssl3 - - task: DownloadSecureFile@1 - name: pmcv4cert - displayName: 'Download cert for PMC v4' - inputs: - secureFile: 'auth.pem' - - ${{ each repo in parameters.openssl3rpmrepos }}: - - script: bash scripts/upload-linux-packages.sh -i $(PMCv4ClientId) -c $(pmcv4cert.secureFilePath) -f $(Build.SourcesDirectory)/artifacts/signed/openssl3/gen -r ${{ repo }} -n "*.rpm" - condition: eq(${{ parameters.debug }}, false) - displayName: ${{ repo }} - continueOnError: true + - ${{ each kernel in parameters.kernel }}: + - ${{ each repo_type in kernel.default }}: + - job: UploadPackage_${{ kernel.name }}_${{ repo_type.name }} + displayName: Upload ${{ kernel.name }} based ${{ repo_type.name }} packages to repos + timeoutInMinutes: 120 + workspace: + clean: all + pool: + vmImage: 'ubuntu-latest' + variables: + - group: MsQuicAADApp + steps: + - task: DownloadPipelineArtifact@2 + inputs: + source: specific + project: $(resources.pipeline.onebranch.projectID) + pipeline: $(resources.pipeline.onebranch.pipelineID) + preferTriggeringPipeline: true + runVersion: specific + runId: $(resources.pipeline.onebranch.runID) + artifact: drop_package_linux_distribution_${{ kernel.name }} + path: $(Build.SourcesDirectory)/artifacts/signed/${{ kernel.name }} + - task: DownloadSecureFile@1 + name: pmcv4cert + displayName: 'Download cert for PMC v4' + inputs: + secureFile: 'auth.pem' + - ${{ if eq(repo_type.name, 'CBL' )}}: + - ${{ each repo in repo_type.destinations }}: + - script: bash scripts/upload-linux-packages.sh -i $(PMCv4ClientId) -c $(pmcv4cert.secureFilePath) -f $(Build.SourcesDirectory)/artifacts/signed/${{ kernel.name }}/cbl -r ${{ repo }} -n "*.rpm" + condition: eq(${{ parameters.debug }}, false) + displayName: ${{ repo }} + continueOnError: true + - ${{ else }}: + - ${{ each repo in repo_type.destinations }}: + - script: bash scripts/upload-linux-packages.sh -i $(PMCv4ClientId) -c $(pmcv4cert.secureFilePath) -f $(Build.SourcesDirectory)/artifacts/signed/${{ kernel.name }}/gen -r ${{ repo }} -n "*.${{ lower(repo_type.name) }}" + condition: eq(${{ parameters.debug }}, false) + displayName: ${{ repo }} + continueOnError: true diff --git a/.azure/OneBranch.PullRequest.yml b/.azure/OneBranch.PullRequest.yml index ac9d0721ac..1b873524c9 100644 --- a/.azure/OneBranch.PullRequest.yml +++ b/.azure/OneBranch.PullRequest.yml @@ -74,10 +74,10 @@ extends: - container: linux_build_container # Default container image: 'ghcr.io/microsoft/msquic/linux-build-xcomp:ubuntu-20.04-cross' type: Linux - - container: ubuntu_2204_cross + - container: kernel5_15_cross image: 'ghcr.io/microsoft/msquic/linux-build-xcomp:ubuntu-22.04-cross' type: Linux - - container: ubuntu_2404_cross + - container: kernel6_8_cross image: 'ghcr.io/microsoft/msquic/linux-build-xcomp:ubuntu-24.04-cross' type: Linux @@ -175,23 +175,23 @@ extends: - template: .azure/obtemplates/build-linux.yml@self parameters: config: Release - os: ubuntu_2204 + kernel: "kernel5_15" tls: openssl3 - template: .azure/obtemplates/build-linux.yml@self parameters: config: Debug - os: ubuntu_2204 + kernel: "kernel5_15" tls: openssl3 - template: .azure/obtemplates/build-linux.yml@self parameters: config: Release - os: ubuntu_2404 + kernel: "kernel6_8" tls: openssl3 xdp: "-UseXdp" - template: .azure/obtemplates/build-linux.yml@self parameters: config: Debug - os: ubuntu_2404 + kernel: "kernel6_8" tls: openssl3 xdp: "-UseXdp" @@ -201,6 +201,14 @@ extends: - build_linux jobs: - template: .azure/obtemplates/build-linux-packages.yml@self + parameters: + kernel: "kernel5_4" + - template: .azure/obtemplates/build-linux-packages.yml@self + parameters: + kernel: "kernel5_15" + - template: .azure/obtemplates/build-linux-packages.yml@self + parameters: + kernel: "kernel6_8" - stage: package_windows displayName: Package Windows diff --git a/.azure/obtemplates/build-distribution.yml b/.azure/obtemplates/build-distribution.yml index 377a6ce3bb..da280a297e 100644 --- a/.azure/obtemplates/build-distribution.yml +++ b/.azure/obtemplates/build-distribution.yml @@ -13,39 +13,39 @@ jobs: - template: ./download-artifacts.yml parameters: platform: linux - linuxos: ubuntu_2004 + kernel: kernel5_4 config: Release tls: openssl - template: ./download-artifacts.yml parameters: platform: linux - linuxos: ubuntu_2004 + kernel: kernel5_4 config: Debug tls: openssl - template: ./download-artifacts.yml parameters: platform: linux - linuxos: ubuntu_2204 + kernel: kernel5_15 config: Release tls: openssl3 - template: ./download-artifacts.yml parameters: platform: linux - linuxos: ubuntu_2204 + kernel: kernel5_15 config: Debug tls: openssl3 - template: ./download-artifacts.yml parameters: platform: linux - linuxos: ubuntu_2404 + kernel: kernel6_8 config: Release tls: openssl3 - template: ./download-artifacts.yml parameters: platform: linux - linuxos: ubuntu_2404 + kernel: kernel6_8 config: Debug tls: openssl3 diff --git a/.azure/obtemplates/build-linux-packages.yml b/.azure/obtemplates/build-linux-packages.yml index 7dee1aa9f4..bf8dbf69be 100644 --- a/.azure/obtemplates/build-linux-packages.yml +++ b/.azure/obtemplates/build-linux-packages.yml @@ -1,25 +1,17 @@ parameters: - sign: false +- name: sign + type: boolean + default: false +- name: kernel + type: string jobs: -- job: distribution +- job: distribution_${{ parameters.kernel }} # artifact becomes drop_package_linux_${{ jobname }} displayName: Distribution - strategy: - matrix: - ubuntu_2004: - os: ubuntu_2004 - tls: openssl - ubuntu_2204: - os: ubuntu_2204 - tls: openssl3 - ubuntu_2404: - os: ubuntu_2404 - tls: openssl3 pool: type: linux variables: ob_outputDirectory: $(Build.SourcesDirectory)/artifacts/dist - ob_artifactSuffix: _$(os)_$(tls) steps: - task: PowerShell@2 displayName: Prepare Build Machine @@ -29,12 +21,12 @@ jobs: arguments: -ForContainerBuild - task: DownloadPipelineArtifact@2 inputs: - artifact: drop_build_linux_build_$(os)_$(tls)_Debug + artifact: drop_build_linux_${{ parameters.kernel }}_Debug path: $(Build.SourcesDirectory)/artifacts/bin/linux pattern: '*.tar' - task: DownloadPipelineArtifact@2 inputs: - artifact: drop_build_linux_build_$(os)_$(tls)_Release + artifact: drop_build_linux_${{ parameters.kernel }}_Release path: $(Build.SourcesDirectory)/artifacts/bin/linux pattern: '*.tar' - script: | # rebuild artifacts with correct permissions and symlink attributes. @@ -46,7 +38,8 @@ jobs: inputs: pwsh: false filePath: scripts/package-distribution.ps1 - arguments: -OS $(os) + ${{ if eq(parameters.kernel, 'kernel6_8') }}: + arguments: -Time64Distro - script: | # prepare 2 sets of packages for signing with different keys (gen = general purpose, cbl = cbl-mariner) mkdir $(Build.SourcesDirectory)/artifacts/dist/gen find $(Build.SourcesDirectory)/artifacts/dist -type f -exec mv -t $(Build.SourcesDirectory)/artifacts/dist/gen/ {} + diff --git a/.azure/obtemplates/build-linux.yml b/.azure/obtemplates/build-linux.yml index 5fd6f8e054..6eb4e59819 100644 --- a/.azure/obtemplates/build-linux.yml +++ b/.azure/obtemplates/build-linux.yml @@ -2,12 +2,12 @@ parameters: config: '' tls: 'openssl' platform: 'linux' - os: 'ubuntu_2004' + kernel: 'kernel5_4' xdp: '' jobs: -- job: build_${{ parameters.os }}_${{ parameters.tls }}_${{ parameters.config }} - displayName: ${{ parameters.os }} ${{ parameters.tls }} ${{ parameters.config }} +- job: ${{ parameters.kernel }}_${{ parameters.config }} # this job name becomes artifact suffix in the build pipeline + displayName: ${{ parameters.platform }} ${{ parameters.kernel }} ${{ parameters.tls }} ${{ parameters.config }} pool: type: linux variables: @@ -17,48 +17,48 @@ jobs: steps: - task: PowerShell@2 displayName: Prepare Build Machine - ${{ if eq(parameters.os, 'ubuntu_2004') }}: + ${{ if eq(parameters.kernel, 'kernel5_4') }}: target: linux_build_container - ${{ elseif eq(parameters.os, 'ubuntu_2204') }}: - target: ubuntu_2204_cross + ${{ elseif eq(parameters.kernel, 'kernel5_15') }}: + target: kernel5_15_cross ${{ else }}: - target: ubuntu_2404_cross + target: kernel6_8_cross inputs: pwsh: true filePath: scripts/prepare-machine.ps1 arguments: -Tls ${{ parameters.tls }} -ForContainerBuild - task: PowerShell@2 displayName: x64 - ${{ if eq(parameters.os, 'ubuntu_2004') }}: + ${{ if eq(parameters.kernel, 'kernel5_4') }}: target: linux_build_container - ${{ elseif eq(parameters.os, 'ubuntu_2204') }}: - target: ubuntu_2204_cross + ${{ elseif eq(parameters.kernel, 'kernel5_15') }}: + target: kernel5_15_cross ${{ else }}: - target: ubuntu_2404_cross + target: kernel6_8_cross inputs: pwsh: true filePath: scripts/build.ps1 arguments: -Tls ${{ parameters.tls }} -Config ${{ parameters.config }} -Platform ${{ parameters.platform }} ${{ parameters.xdp }} -Arch x64 -CI -UseSystemOpenSSLCrypto -OneBranch -OfficialRelease - task: PowerShell@2 displayName: arm64 - ${{ if eq(parameters.os, 'ubuntu_2004') }}: + ${{ if eq(parameters.kernel, 'kernel5_4') }}: target: linux_build_container - ${{ elseif eq(parameters.os, 'ubuntu_2204') }}: - target: ubuntu_2204_cross + ${{ elseif eq(parameters.kernel, 'kernel5_15') }}: + target: kernel5_15_cross ${{ else }}: - target: ubuntu_2404_cross + target: kernel6_8_cross inputs: pwsh: true filePath: scripts/build.ps1 arguments: -Tls ${{ parameters.tls }} -Config ${{ parameters.config }} -Platform ${{ parameters.platform }} -Arch arm64 -CI -UseSystemOpenSSLCrypto -OneBranch -OfficialRelease - task: PowerShell@2 displayName: arm - ${{ if eq(parameters.os, 'ubuntu_2004') }}: + ${{ if eq(parameters.kernel, 'kernel5_4') }}: target: linux_build_container - ${{ elseif eq(parameters.os, 'ubuntu_2204') }}: - target: ubuntu_2204_cross + ${{ elseif eq(parameters.kernel, 'kernel5_15') }}: + target: kernel5_15_cross ${{ else }}: - target: ubuntu_2404_cross + target: kernel6_8_cross inputs: pwsh: true filePath: scripts/build.ps1 diff --git a/.azure/obtemplates/download-artifacts.yml b/.azure/obtemplates/download-artifacts.yml index d6a92f31dd..7958379514 100644 --- a/.azure/obtemplates/download-artifacts.yml +++ b/.azure/obtemplates/download-artifacts.yml @@ -2,7 +2,7 @@ parameters: platform: '' - linuxos: 'ubuntu_2004' + kernel: 'kernel5_4' tls: '' config: '' @@ -16,7 +16,7 @@ steps: runVersion: specific runId: $(resources.pipeline.onebranch.runID) ${{ if eq(parameters.platform, 'linux') }}: - artifact: drop_build_${{ parameters.platform }}_build_${{ parameters.linuxos }}_${{ parameters.tls }}_${{ parameters.config }} + artifact: drop_build_${{ parameters.platform }}_${{ parameters.kernel }}_${{ parameters.config }} ${{ else }}: artifact: drop_build_${{ parameters.platform }}_build_${{ parameters.platform }}_${{ parameters.tls }}_${{ parameters.config }} path: $(Build.SourcesDirectory)/artifacts/bin/${{ parameters.platform }} diff --git a/.github/workflows/build-reuse-darwin-framework.yml b/.github/workflows/build-reuse-darwin-framework.yml index 86891dab94..858158f72d 100644 --- a/.github/workflows/build-reuse-darwin-framework.yml +++ b/.github/workflows/build-reuse-darwin-framework.yml @@ -71,7 +71,7 @@ jobs: shell: pwsh run: scripts/merge-darwin.ps1 -DeleteSource -Config ${{ inputs.config }} - name: Upload build artifacts - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: ${{ inputs.config }}-macos-macos-12-universal-${{ inputs.tls }}${{ inputs.static }} path: artifacts @@ -103,7 +103,7 @@ jobs: shell: pwsh run: scripts/package-darwin-framework.ps1 -Config ${{ inputs.config }} -Platform ${{ matrix.vec.plat }} -Arch ${{ matrix.vec.arch }} - name: Upload build artifacts - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: Framework-${{ inputs.config }}-${{ matrix.vec.plat }}-macos-12-${{ matrix.vec.arch }}-${{ inputs.tls }}${{ inputs.static }} path: artifacts @@ -137,7 +137,7 @@ jobs: shell: pwsh run: scripts/package-darwin-xcframework.ps1 -Config ${{ inputs.config }} - name: Upload build artifacts - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: XCFramework-${{ inputs.config }} path: artifacts/frameworks diff --git a/.github/workflows/build-reuse-unix.yml b/.github/workflows/build-reuse-unix.yml index 8aab91ceb8..fa4859efb9 100644 --- a/.github/workflows/build-reuse-unix.yml +++ b/.github/workflows/build-reuse-unix.yml @@ -114,7 +114,7 @@ jobs: shell: pwsh run: scripts/build.ps1 -Config ${{ inputs.config }} -Platform ${{ inputs.plat }} -Arch ${{ inputs.arch }} -Tls ${{ inputs.tls }} ${{ inputs.static }} ${{ inputs.clang }} ${{ inputs.systemcrypto }} ${{ inputs.codecheck }} ${{ inputs.sanitize }} ${{ inputs.xdp }} -OneBranch - name: Upload build artifacts - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: ${{ inputs.config }}-${{ inputs.plat }}-${{ inputs.os }}-${{ inputs.arch }}-${{ inputs.tls }}${{ inputs.static }}${{ inputs.clang }}${{ inputs.systemcrypto }}${{ inputs.codecheck }}${{ inputs.sanitize }}${{ inputs.xdp }}${{ inputs.build }} path: artifacts diff --git a/.github/workflows/build-reuse-win.yml b/.github/workflows/build-reuse-win.yml index 8cbab25857..c56b74b957 100644 --- a/.github/workflows/build-reuse-win.yml +++ b/.github/workflows/build-reuse-win.yml @@ -74,7 +74,7 @@ jobs: repository: microsoft/msquic ref: ${{ inputs.ref }} - name: Install Perl - uses: shogo82148/actions-setup-perl@f551dafcc94572adc179bbddbb409b3ada8f8ff5 + uses: shogo82148/actions-setup-perl@9c1eca9952ccc07f9ca4a2097b63df93d9d138e9 with: perl-version: '5.34' - name: Install NASM @@ -101,7 +101,7 @@ jobs: Remove-Item artifacts/corenet-ci-main -Recurse -Force -ErrorAction Ignore Remove-Item artifacts/xdp -Recurse -Force -ErrorAction Ignore - name: Upload build artifacts - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: ${{ inputs.config }}-${{ inputs.plat }}-${{ inputs.os }}-${{ inputs.arch }}-${{ inputs.tls }}${{ inputs.sanitize }}${{ inputs.static }}${{ inputs.build }} path: artifacts diff --git a/.github/workflows/build-reuse-winkernel.yml b/.github/workflows/build-reuse-winkernel.yml index 2ae53fa6a7..2fac6b1a40 100644 --- a/.github/workflows/build-reuse-winkernel.yml +++ b/.github/workflows/build-reuse-winkernel.yml @@ -88,7 +88,7 @@ jobs: Remove-Item artifacts/corenet-ci-main -Recurse -Force -ErrorAction Ignore Remove-Item artifacts/xdp -Recurse -Force -ErrorAction Ignore - name: Upload build artifacts - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: ${{ inputs.config }}-${{ inputs.plat }}-${{ inputs.os }}-${{ inputs.arch }}-${{ inputs.tls }}${{ inputs.build }} path: artifacts diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0610d695f3..164a2d35d6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -236,7 +236,7 @@ jobs: shell: pwsh run: scripts/package-nuget.ps1 -Tls ${{ matrix.vec.tls }} ${{ matrix.vec.arg }} -GHA - name: Upload build artifacts - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: Nuget-Release-${{ matrix.vec.plat }}-windows-2022-arm64-${{ matrix.vec.tls }} path: artifacts/dist/*.nupkg diff --git a/.github/workflows/cargo.yml b/.github/workflows/cargo.yml index 251c915a4f..02f7a748c3 100644 --- a/.github/workflows/cargo.yml +++ b/.github/workflows/cargo.yml @@ -21,7 +21,7 @@ jobs: name: Cargo steps: - name: Harden Runner - uses: step-security/harden-runner@0d381219ddf674d61a7572ddd19d7941e271515c + uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde with: egress-policy: audit - name: Checkout repository @@ -31,7 +31,7 @@ jobs: shell: pwsh - name: Install Perl if: runner.os == 'Windows' - uses: shogo82148/actions-setup-perl@f551dafcc94572adc179bbddbb409b3ada8f8ff5 + uses: shogo82148/actions-setup-perl@9c1eca9952ccc07f9ca4a2097b63df93d9d138e9 with: perl-version: '5.34' - name: Install NASM diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index 7dc4c911f8..f907b71bac 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -21,7 +21,7 @@ jobs: dry-run: false language: c - name: Upload Crash - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 if: failure() && steps.build.outcome == 'success' with: name: artifacts diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 132061549f..f33a563437 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -76,7 +76,7 @@ jobs: continue-on-error: true run: scripts/test.ps1 -NoProgress -IsolationMode Batch -SkipUnitTests -CodeCoverage -Config ${{ matrix.vec.config }} -Arch ${{ matrix.vec.arch }} -Tls ${{ matrix.vec.tls }} -LogProfile Full.Light ${{ matrix.vec.xdp }} ${{ matrix.vec.qtip }} - name: Upload Results - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: BVT-${{ matrix.vec.config }}-${{ matrix.vec.plat }}-${{ matrix.vec.os }}-${{ matrix.vec.arch }}-${{ matrix.vec.tls }}${{ matrix.vec.qtip }}${{ matrix.vec.systemcrypto }}${{ matrix.vec.sanitize }} path: artifacts/coverage/*.cov @@ -126,7 +126,7 @@ jobs: shell: pwsh run: scripts/spin.ps1 -Config ${{ matrix.vec.config }} -Arch ${{ matrix.vec.arch }} -Tls ${{ matrix.vec.tls }} -Timeout ${{ env.main-timeout }} -RepeatCount ${{ env.main-repeat }} -AllocFail ${{ env.main-allocfail }} ${{ matrix.vec.xdp }} -CodeCoverage -LogProfile Basic.Light - name: Upload Results - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: Spin-${{ matrix.vec.config }}-${{ matrix.vec.plat }}-${{ matrix.vec.os }}-${{ matrix.vec.arch }}-${{ matrix.vec.tls }}${{ matrix.vec.xdp }}${{ matrix.vec.sanitize }} path: artifacts/coverage/*.cov @@ -172,7 +172,7 @@ jobs: shell: pwsh run: scripts/recvfuzz.ps1 -Config ${{ matrix.vec.config }} -Arch ${{ matrix.vec.arch }} -Tls ${{ matrix.vec.tls }} -timeout ${{ env.main-timeout }} ${{ matrix.vec.xdp }} -CodeCoverage -LogProfile Basic.Light - name: Upload Results - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: RecvFuzz-${{ matrix.vec.config }}-${{ matrix.vec.plat }}-${{ matrix.vec.os }}-${{ matrix.vec.arch }}-${{ matrix.vec.tls }}${{ matrix.vec.xdp }}${{ matrix.vec.sanitize }} path: artifacts/coverage/*.cov @@ -216,7 +216,7 @@ jobs: shell: pwsh run: scripts/merge-coverage.ps1 -Config Debug -Arch x64 -Tls openssl - name: Upload Results - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: merged path: artifacts\coverage\windows\x64_Debug_openssl\msquiccoverage.xml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 330d4605cd..4baceb8146 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -27,7 +27,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@0d381219ddf674d61a7572ddd19d7941e271515c + uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde with: egress-policy: audit - name: Checkout repository @@ -51,7 +51,7 @@ jobs: cmake --build . --target OpenSSL_Target - name: Initialize CodeQL - uses: github/codeql-action/init@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a + uses: github/codeql-action/init@4dd16135b69a43b6c8efb853346f8437d92d3c93 with: languages: cpp config-file: ./.github/codeql/codeql-config.yml @@ -62,4 +62,4 @@ jobs: cmake --build . - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a + uses: github/codeql-action/analyze@4dd16135b69a43b6c8efb853346f8437d92d3c93 diff --git a/.github/workflows/docker-publish-xcomp.yml b/.github/workflows/docker-publish-xcomp.yml index 5b7e0f3a5d..a211a993ba 100644 --- a/.github/workflows/docker-publish-xcomp.yml +++ b/.github/workflows/docker-publish-xcomp.yml @@ -40,7 +40,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@0d381219ddf674d61a7572ddd19d7941e271515c + uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde with: egress-policy: audit @@ -68,7 +68,7 @@ jobs: # Build and push Docker image with Buildx (don't push on PR) # https://github.com/docker/build-push-action - name: Build and push Docker image - uses: docker/build-push-action@5176d81f87c23d6fc96624dfdbcd9f3830bbe445 + uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85 with: context: .docker/ubuntu-${{ matrix.version }} file: .docker/ubuntu-${{ matrix.version }}/Dockerfile diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index e2047433f9..accaa171f5 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -26,7 +26,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@0d381219ddf674d61a7572ddd19d7941e271515c + uses: step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde with: egress-policy: audit - name: Checkout repository @@ -55,7 +55,7 @@ jobs: # Build and push Docker image with Buildx (don't push on PR) # https://github.com/docker/build-push-action - name: Build and push Docker image - uses: docker/build-push-action@5176d81f87c23d6fc96624dfdbcd9f3830bbe445 + uses: docker/build-push-action@5cd11c3a4ced054e52742c5fd54dca954e0edd85 with: context: . file: scripts/qns.Dockerfile diff --git a/.github/workflows/package-linux.yml b/.github/workflows/package-linux.yml index 18e3846969..82bbab8916 100644 --- a/.github/workflows/package-linux.yml +++ b/.github/workflows/package-linux.yml @@ -33,9 +33,9 @@ jobs: { config: "Release", os: "ubuntu-22.04", arch: "arm", tls: "openssl3" }, { config: "Release", os: "ubuntu-22.04", arch: "arm64", tls: "openssl3" }, { config: "Release", os: "ubuntu-22.04", arch: "x64", tls: "openssl3" }, - { config: "Release", os: "ubuntu-24.04", arch: "arm", tls: "openssl3" }, - { config: "Release", os: "ubuntu-24.04", arch: "arm64", tls: "openssl3" }, - { config: "Release", os: "ubuntu-24.04", arch: "x64", tls: "openssl3", xdp: "-UseXdp" }, + { config: "Release", os: "ubuntu-24.04", arch: "arm", tls: "openssl3", time64: "-Time64Distro" }, + { config: "Release", os: "ubuntu-24.04", arch: "arm64", tls: "openssl3", time64: "-Time64Distro" }, + { config: "Release", os: "ubuntu-24.04", arch: "x64", tls: "openssl3", xdp: "-UseXdp", time64: "-Time64Distro" }, ] uses: ./.github/workflows/package-reuse-linux.yml with: @@ -44,6 +44,7 @@ jobs: arch: ${{ matrix.vec.arch }} tls: ${{ matrix.vec.tls }} xdp: ${{ matrix.vec.xdp }} + time64: ${{ matrix.vec.time64 }} test-packages: name: Test Linux Packages @@ -58,13 +59,6 @@ jobs: ] runs-on: ${{ matrix.vec.os }} steps: - - name: Checkout repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 - with: - fetch-depth: 0 - - name: Prepare Machine - shell: pwsh - run: scripts/prepare-machine.ps1 -ForTest ${{ matrix.vec.xdp }} - name: Download Package uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 with: @@ -80,10 +74,76 @@ jobs: sudo apt-add-repository ppa:lttng/stable-2.13 sudo apt-get update sudo apt-get install -y lttng-tools - sudo find -name "*.deb" -exec dpkg -i {} \; + sudo find -name "*.deb" -exec sudo apt install -y ./{} \; rm artifacts/bin/linux/${{ matrix.vec.arch }}_${{ matrix.vec.config }}_${{ matrix.vec.tls }}/libmsquic.so* ls artifacts/bin/linux/${{ matrix.vec.arch }}_${{ matrix.vec.config }}_${{ matrix.vec.tls }} - name: Test run: | chmod +x artifacts/bin/linux/${{ matrix.vec.arch }}_${{ matrix.vec.config }}_${{ matrix.vec.tls }}/msquictest artifacts/bin/linux/${{ matrix.vec.arch }}_${{ matrix.vec.config }}_${{ matrix.vec.tls }}/msquictest --gtest_filter=ParameterValidation.ValidateApi + test-packages-on-docker: + name: Test Linux Packages + needs: [build-packages] + strategy: + fail-fast: false + matrix: + vec: [ + # Ubuntu 24.04 + { friendlyName: "Ubuntu 24.04 x64", config: "Release", os: "ubuntu-24.04", arch: "x64", tls: "openssl3", image: "mcr.microsoft.com/dotnet/sdk:9.0-preview-noble-amd64", xdp: "-UseXdp", dotnetVersion: "9.0" }, + { friendlyName: "Ubuntu 24.04 ARM32", config: "Release", os: "ubuntu-24.04", arch: "arm", tls: "openssl3", image: "mcr.microsoft.com/dotnet/sdk:9.0-preview-noble-arm32v7", dotnetVersion: "9.0" }, + { friendlyName: "Ubuntu 24.04 ARM64", config: "Release", os: "ubuntu-24.04", arch: "arm64", tls: "openssl3", image: "mcr.microsoft.com/dotnet/sdk:9.0-preview-noble-arm64v8", dotnetVersion: "9.0" }, + # Ubuntu 22.04 + { friendlyName: "Ubuntu 22.04 x64", config: "Release", os: "ubuntu-22.04", arch: "x64", tls: "openssl3", image: "mcr.microsoft.com/dotnet/runtime:8.0-jammy-amd64", dotnetVersion: "8.0" }, + { friendlyName: "Ubuntu 22.04 ARM32", config: "Release", os: "ubuntu-22.04", arch: "arm", tls: "openssl3", image: "mcr.microsoft.com/dotnet/runtime:8.0-jammy-arm32v7", dotnetVersion: "8.0" }, + { friendlyName: "Ubuntu 22.04 ARM64", config: "Release", os: "ubuntu-22.04", arch: "arm64", tls: "openssl3", image: "mcr.microsoft.com/dotnet/runtime:8.0-jammy-arm64v8", dotnetVersion: "8.0" }, + # Ubuntu 20.04 + { friendlyName: "Ubuntu 20.04 x64", config: "Release", os: "ubuntu-20.04", arch: "x64", tls: "openssl", image: "mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-helix-amd64", dotnetVersion: "9.0" }, + { friendlyName: "Ubuntu 20.04 ARM64", config: "Release", os: "ubuntu-20.04", arch: "arm64", tls: "openssl", image: "mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-helix-arm64v8", dotnetVersion: "9.0" }, + # Debian 12 + { friendlyName: "Debian 12 x64", config: "Release", os: "ubuntu-22.04", arch: "x64", tls: "openssl3", image: "mcr.microsoft.com/dotnet/sdk:9.0-preview-bookworm-slim-amd64", dotnetVersion: "9.0" }, + { friendlyName: "Debian 12 ARM32", config: "Release", os: "ubuntu-22.04", arch: "arm", tls: "openssl3", image: "mcr.microsoft.com/dotnet/sdk:9.0-preview-bookworm-slim-arm32v7", dotnetVersion: "9.0" }, + { friendlyName: "Debian 12 ARM64", config: "Release", os: "ubuntu-22.04", arch: "arm64", tls: "openssl3", image: "mcr.microsoft.com/dotnet/sdk:9.0-preview-bookworm-slim-arm64v8", dotnetVersion: "9.0" }, + # CBL-Mariner 2.0 + { friendlyName: "CBL-Mariner 2.0 x64", config: "Release", os: "ubuntu-20.04", arch: "x64", tls: "openssl", image: "mcr.microsoft.com/dotnet/runtime:8.0-cbl-mariner2.0-amd64", dotnetVersion: "8.0" }, + { friendlyName: "CBL-Mariner 2.0 ARM64", config: "Release", os: "ubuntu-20.04", arch: "arm64", tls: "openssl", image: "mcr.microsoft.com/dotnet/runtime:8.0-cbl-mariner2.0-arm64v8", dotnetVersion: "8.0" }, + # Azure Linux 3.0 + { friendlyName: "AzureLinux 3.0 x64", config: "Release", os: "ubuntu-24.04", arch: "x64", tls: "openssl3", image: "mcr.microsoft.com/dotnet/sdk:9.0-preview-azurelinux3.0-amd64", dotnetVersion: "9.0", xdp: "-UseXdp" }, + { friendlyName: "AzureLinux 3.0 ARM64", config: "Release", os: "ubuntu-24.04", arch: "arm64", tls: "openssl3", image: "mcr.microsoft.com/dotnet/sdk:9.0-preview-azurelinux3.0-arm64v8", dotnetVersion: "9.0" }, + # Centos Stream 9 + { friendlyName: "CentOS Stream 9 x64", config: "Release", os: "ubuntu-22.04", arch: "x64", tls: "openssl3", image: "mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream9-helix", dotnetVersion: "9.0" }, + # Fedora 39 - 40 + { friendlyName: "Fedora 39 x64", config: "Release", os: "ubuntu-22.04", arch: "x64", tls: "openssl3", image: "mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-39", dotnetVersion: "9.0" }, + { friendlyName: "Fedora 40 x64", config: "Release", os: "ubuntu-22.04", arch: "x64", tls: "openssl3", image: "mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-40", dotnetVersion: "9.0" }, + # OpenSuse 15.4 + { friendlyName: "OpenSuse 15.4 x64", config: "Release", os: "ubuntu-20.04", arch: "x64", tls: "openssl", image: "mcr.microsoft.com/dotnet-buildtools/prereqs:opensuse-15.4-helix-amd64", dotnetVersion: "9.0" }, + # RHEL 8 - 9 + # { config: "Release", os: "ubuntu-24.04", arch: "x64", tls: "openssl3", image: "redhat/ubi8-minimal:latest" }, + # { config: "Release", os: "ubuntu-24.04", arch: "x64", tls: "openssl3", image: "redhat/ubi9-minimal:latest" }, + ] + runs-on: ${{ matrix.vec.os }} + steps: + - name: Checkout Repository + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - name: Download Package + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 + with: + name: Package-${{ matrix.vec.config }}-linux-${{ matrix.vec.os }}-${{ matrix.vec.arch }}-${{ matrix.vec.tls }}-UseSystemOpenSSLCrypto${{ matrix.vec.xdp }} + path: artifacts + - name: Download Build Artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 + with: + name: ${{ matrix.vec.config }}-linux-${{ matrix.vec.os }}-${{ matrix.vec.arch }}-${{ matrix.vec.tls }}-UseSystemOpenSSLCrypto${{ matrix.vec.xdp }} + path: artifacts + - name: Set up QEMU + uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf + - name: Set up .NET 9.0 + uses: actions/setup-dotnet@6bd8b7f7774af54e05809fcc5431931b3eb1ddee + with: + dotnet-version: ${{ matrix.vec.dotnetVersion }} + - name: Build .NET QUIC Test Project + run: | + pushd src/cs/QuicSimpleTest && dotnet build QuicHello.net${{ matrix.vec.dotnetVersion }}.csproj -a ${{ matrix.vec.arch }} -c ${{ matrix.vec.config }} -o artifacts/net${{ matrix.vec.dotnetVersion }} -f net${{ matrix.vec.dotnetVersion }} && popd + - name: Docker Run + run: | + docker run -v $(pwd):/main ${{ matrix.vec.image }} /main/scripts/docker-script.sh ${{ matrix.vec.arch }} ${{ matrix.vec.config }} ${{ matrix.vec.tls }} ${{ matrix.vec.dotnetVersion }} + \ No newline at end of file diff --git a/.github/workflows/package-reuse-linux.yml b/.github/workflows/package-reuse-linux.yml index 6f4118d6e2..0cbc84a0dc 100644 --- a/.github/workflows/package-reuse-linux.yml +++ b/.github/workflows/package-reuse-linux.yml @@ -54,6 +54,10 @@ on: required: false default: '' type: string + time64: + required: false + default: '' + type: string permissions: read-all @@ -96,9 +100,9 @@ jobs: find -name "*.tar" -exec tar -xvf '{}' \; - name: Build Package shell: pwsh - run: scripts/package-distribution.ps1 + run: scripts/package-distribution.ps1 ${{ inputs.time64 }} - name: Upload build artifacts - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: Package-${{ inputs.config }}-linux-${{ inputs.os }}-${{ inputs.arch }}-${{ inputs.tls }}-UseSystemOpenSSLCrypto${{ inputs.sanitize }}${{ inputs.xdp }}${{ inputs.build }} path: artifacts/dist diff --git a/.github/workflows/plugins.yml b/.github/workflows/plugins.yml index 9581d2e40c..39bab191ab 100644 --- a/.github/workflows/plugins.yml +++ b/.github/workflows/plugins.yml @@ -30,7 +30,7 @@ jobs: uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce - name: Build run: msbuild src\plugins\msquic.windbg.sln /p:configuration=${{ matrix.configuration }} /p:platform=${{ matrix.platform }} - - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: bin_windbg_${{ matrix.configuration }}_${{ matrix.platform }} path: | @@ -54,15 +54,14 @@ jobs: uses: actions/setup-dotnet@6bd8b7f7774af54e05809fcc5431931b3eb1ddee with: dotnet-version: 6.0.x + - name: Install Dependencies + run: dotnet tool install --global Microsoft.Performance.Toolkit.Plugins.Cli --version 0.1.25-preview - name: Build run: dotnet build src\plugins\QuicTrace.sln -c ${{ matrix.configuration }} - - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: bin_quictrace_${{ matrix.configuration }} path: artifacts/bin/quictrace/${{ matrix.configuration }} - # Package the plugin - - name: Install plugintool - run: dotnet tool install --global Microsoft.Performance.Toolkit.Plugins.Cli --version 0.1.25-preview - name: Package shell: pwsh run: | @@ -74,7 +73,7 @@ jobs: $packageName = "$pluginId-$pluginVersion.ptix" Write-Host "Creating $packageName" & plugintool pack -s $sourceDir -o "artifacts/bin/quictrace/$packageName" - - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: ptix_quictrace_${{ matrix.configuration }} path: artifacts/bin/quictrace/*.ptix diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index 21e1d47bf7..5509a84b82 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -43,7 +43,7 @@ jobs: # Upload the results as artifacts (optional). - name: "Upload artifact" - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: SARIF file path: results.sarif @@ -51,6 +51,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a + uses: github/codeql-action/upload-sarif@4dd16135b69a43b6c8efb853346f8437d92d3c93 with: sarif_file: results.sarif diff --git a/.github/workflows/stress.yml b/.github/workflows/stress.yml index 004edd4839..b2c11bfc7b 100644 --- a/.github/workflows/stress.yml +++ b/.github/workflows/stress.yml @@ -132,7 +132,7 @@ jobs: run: | sudo chmod -R 777 artifacts - name: Upload on Failure - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 if: failure() with: name: stress-${{ matrix.vec.config }}-${{ matrix.vec.plat }}-${{ matrix.vec.os }}-${{ matrix.vec.arch }}-${{ matrix.vec.tls }}${{ matrix.vec.xdp }}${{ matrix.vec.sanitize }} @@ -188,7 +188,7 @@ jobs: shell: pwsh run: scripts/recvfuzz.ps1 -AZP -Config ${{ matrix.vec.config }} -Arch ${{ matrix.vec.arch }} -Tls ${{ matrix.vec.tls }} -timeout ${{ env.main-timeout }} ${{ matrix.vec.xdp }} - name: Upload on Failure - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 if: failure() with: name: recvfuzz-${{ matrix.vec.config }}-${{ matrix.vec.plat }}-${{ matrix.vec.os }}-${{ matrix.vec.arch }}-${{ matrix.vec.tls }}${{ matrix.vec.xdp }}${{ matrix.vec.sanitize }} diff --git a/.github/workflows/test-down-level.yml b/.github/workflows/test-down-level.yml index 5fc3249476..51cc5c8f8d 100644 --- a/.github/workflows/test-down-level.yml +++ b/.github/workflows/test-down-level.yml @@ -48,7 +48,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 - name: Install Perl if: runner.os == 'Windows' - uses: shogo82148/actions-setup-perl@f551dafcc94572adc179bbddbb409b3ada8f8ff5 + uses: shogo82148/actions-setup-perl@9c1eca9952ccc07f9ca4a2097b63df93d9d138e9 with: perl-version: '5.34' - name: Install NASM diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 065ba20653..5253831fd4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,6 +2,11 @@ name: BVT on: workflow_dispatch: + inputs: + ref: + required: false + default: '' + type: string push: branches: - main @@ -37,6 +42,7 @@ jobs: arch: ${{ matrix.vec.arch }} tls: ${{ matrix.vec.tls }} build: ${{ matrix.vec.build }} + ref: ${{ inputs.ref || '' }} build-windows: name: Build WinUser @@ -59,6 +65,7 @@ jobs: tls: ${{ matrix.vec.tls }} sanitize: ${{ matrix.vec.sanitize }} build: ${{ matrix.vec.build }} + ref: ${{ inputs.ref || '' }} build-unix: name: Build Unix @@ -86,6 +93,7 @@ jobs: sanitize: ${{ matrix.vec.sanitize }} build: ${{ matrix.vec.build }} xdp: ${{ matrix.vec.xdp }} + ref: ${{ inputs.ref || '' }} bvt: name: BVT @@ -120,6 +128,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + with: + ref: ${{ inputs.ref || '' }} - name: Download Build Artifacts uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 if: matrix.vec.plat == 'windows' @@ -162,7 +172,7 @@ jobs: run: | sudo chmod -R 777 artifacts - name: Upload on Failure - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 if: failure() with: name: BVT-${{ matrix.vec.config }}-${{ matrix.vec.plat }}-${{ matrix.vec.os }}-${{ matrix.vec.arch }}-${{ matrix.vec.tls }}${{ matrix.vec.xdp }}${{ matrix.vec.qtip }}${{ matrix.vec.systemcrypto }}${{ matrix.vec.sanitize }} @@ -184,6 +194,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + with: + ref: ${{ inputs.ref || '' }} - name: Download Build Artifacts uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 with: # note we always use binaries built on windows-2022. @@ -207,9 +219,9 @@ jobs: - name: Test shell: pwsh timeout-minutes: 90 - run: scripts/test.ps1 -Config ${{ matrix.vec.config }} -Arch ${{ matrix.vec.arch }} -Tls ${{ matrix.vec.tls }} -GHA -LogProfile Full.Light -GenerateXmlResults -Kernel -Filter -*ValidateConfiguration:*ValidAlpnLengths:*ResumeRejection*:*ClientCertificate*:*LoadBalanced* + run: scripts/test.ps1 -Config ${{ matrix.vec.config }} -Arch ${{ matrix.vec.arch }} -Tls ${{ matrix.vec.tls }} -OsRunner ${{ matrix.vec.os }} -GHA -LogProfile Full.Light -GenerateXmlResults -Kernel -Filter -*ValidateConfiguration:*ValidAlpnLengths:*ResumeRejection*:*ClientCertificate*:*LoadBalanced* - name: Upload on Failure - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 if: failure() with: name: BVT-Kernel-${{ matrix.vec.config }}-${{ matrix.vec.plat }}-${{ matrix.vec.os }}-${{ matrix.vec.arch }}-${{ matrix.vec.tls }} @@ -233,6 +245,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 with: fetch-depth: 0 + ref: ${{ inputs.ref || '' }} - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 with: name: ${{ matrix.vec.config }}-${{ matrix.vec.plat }}-${{ matrix.vec.os }}-${{ matrix.vec.arch }}-${{ matrix.vec.tls }}${{ matrix.vec.sanitize }}${{ matrix.vec.build }} @@ -244,7 +257,7 @@ jobs: shell: pwsh run: scripts/interop.ps1 -Config ${{ matrix.vec.config }} -Arch ${{ matrix.vec.arch }} -Tls ${{ matrix.vec.tls }} -GHA -GenerateXmlResults - name: Upload results - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: InteropWinlatest-${{ matrix.vec.config }}-${{ matrix.vec.plat }}-${{ matrix.vec.os }}-${{ matrix.vec.arch }}-${{ matrix.vec.tls }}${{ matrix.vec.xdp }} path: artifacts diff --git a/.github/workflows/wan-perf.yml b/.github/workflows/wan-perf.yml index bdaf520134..1cbf12b6d2 100644 --- a/.github/workflows/wan-perf.yml +++ b/.github/workflows/wan-perf.yml @@ -42,7 +42,7 @@ jobs: - name: Prepare Machine shell: pwsh run: scripts/build.ps1 -Config Release -DisableTest -DisableTools - - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: bin path: | @@ -100,12 +100,12 @@ jobs: shell: pwsh run: scripts/emulated-performance.ps1 -Debug -Protocol ('QUIC','TCPTLS') -LogProfile Performance.Light -NoDateLogDir -NumIterations ${{ env.iterations }} -DurationMs ${{ env.duration }} -Pacing ${{ env.pacing }} -BottleneckMbps ${{ matrix.rate }} -RttMs ${{ matrix.rtt }} -BottleneckQueueRatio ${{ matrix.queueRatio }} -RandomLossDenominator ${{ env.loss }} -RandomReorderDenominator ${{ env.reorder }} -ReorderDelayDeltaMs ${{ env.delay }} -BaseRandomSeed ${{ env.seed }} -CongestionControl ${{ env.congestionControl }} - name: Upload Results - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: data path: artifacts/PerfDataResults/windows/x64_Release_schannel/WAN/*.json - name: Upload Logs - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: ${{ format('logs.{0}mbps.{1}ms', matrix.rate, matrix.rtt) }} path: artifacts/logs/wanperf/*.etl @@ -127,7 +127,7 @@ jobs: shell: pwsh run: scripts/emulated-performance.ps1 -MergeDataFiles - name: Upload CSV - uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 with: name: csv path: artifacts\PerfDataResults\windows\x64_Release_schannel\WAN\wan_data.csv diff --git a/CMakeLists.txt b/CMakeLists.txt index 16b925db39..f113a371a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,6 +85,7 @@ option(QUIC_BUILD_PERF "Builds the perf code" OFF) option(QUIC_BUILD_SHARED "Builds msquic as a dynamic library" ON) option(QUIC_ENABLE_LOGGING "Enables logging" OFF) option(QUIC_ENABLE_SANITIZERS "Enables sanitizers" OFF) +option(QUIC_ENABLE_POOL_ALLOC "Enables pool allocations" ON) option(QUIC_STATIC_LINK_CRT "Statically links the C runtime" ON) option(QUIC_STATIC_LINK_PARTIAL_CRT "Statically links the compiler-specific portion of the C runtime" ON) option(QUIC_UWP_BUILD "Build for UWP" OFF) @@ -332,7 +333,7 @@ if(QUIC_HIGH_RES_TIMERS) list(APPEND QUIC_COMMON_DEFINES QUIC_HIGH_RES_TIMERS=1) endif() -if (QUIC_ENABLE_SANITIZERS) +if (QUIC_ENABLE_SANITIZERS OR NOT QUIC_ENABLE_POOL_ALLOC) list(APPEND QUIC_COMMON_DEFINES DISABLE_CXPLAT_POOL=1) endif() diff --git a/scripts/docker-script.sh b/scripts/docker-script.sh new file mode 100755 index 0000000000..5a10c48048 --- /dev/null +++ b/scripts/docker-script.sh @@ -0,0 +1,84 @@ +#! /bin/bash + +if [[ $(id -u) -ne 0 ]]; +then + #Beware of how you compose the command + echo "This script must be run as root. Running the script with sudo..." + printf -v cmd_str '%q ' "$0" "$@" + exec sudo su -c "$cmd_str" + exit $? +fi + +cd /main +. /etc/os-release +OS=$(echo $ID | xargs) +VERSION=$(echo $VERSION_ID | xargs) + +echo "${OS} ${VERSION} is detected." + +install_dependencies_apt() +{ + apt-get update + if ! [ -f /usr/bin/dotnet ]; then + apt-get install -y wget gzip tar + fi + apt-get install -y ./artifacts/libmsquic_*.deb +} + +install_dependencies_rpm() +{ + yum update -y + if ! [ -f /usr/bin/dotnet ]; then + yum install -y wget gzip tar # .NET installing requirements + yum install -y libicu # .NET dependencies + fi + find -name "libmsquic*.rpm" -exec yum localinstall -y {} \; +} + +install_dependencies_opensuse() +{ + zypper ref + if ! [ -f /usr/bin/dotnet ]; then + zypper install -y wget gzip + fi + find -name "libmsquic*.rpm" -exec zypper install --allow-unsigned-rpm -y {} \; +} + +# .NET is installed already on Azure Linux and Mariner images +install_libmsquic_azure_linux() +{ + if ! [ -f /usr/bin/dotnet ]; then + tdnf install -y wget gzip tar + fi + tdnf update + find -name "libmsquic*.rpm" -exec tdnf install -y {} \; +} + +if [[ "$OS" == "ubuntu" ]] || [[ "$OS" == "debian" ]]; then + install_dependencies_apt +elif [[ "$OS" == "centos" ]] || [[ "$OS" == "almalinux" ]] || [[ "$OS" == "rhel" ]] || [[ "$OS" == "fedora" ]]; then + install_dependencies_rpm +elif [[ "$OS" == 'opensuse-leap' ]]; then + install_dependencies_opensuse +elif [[ "$OS" == 'azurelinux' ]] || [[ "$OS" == 'mariner' ]]; then + install_libmsquic_azure_linux +else + echo "Unsupported OS: ${OS}" + exit 1 +fi + +set -e +chmod +x artifacts/bin/linux/${1}_${2}_${3}/msquictest +artifacts/bin/linux/${1}_${2}_${3}/msquictest --gtest_filter=ParameterValidation.ValidateApi + +# Install .NET if it is not installed +if ! [ -f /usr/bin/dotnet ]; then + wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh + chmod +x dotnet-install.sh + ./dotnet-install.sh --channel $4 --shared-runtime + + export PATH=$PATH:$HOME/.dotnet + export DOTNET_ROOT=$HOME/.dotnet +fi + +dotnet /main/src/cs/QuicSimpleTest/artifacts/net$4/QuicHello.net$4.dll diff --git a/scripts/make-packages.sh b/scripts/make-packages.sh index c6afc20235..c60375221a 100755 --- a/scripts/make-packages.sh +++ b/scripts/make-packages.sh @@ -139,18 +139,41 @@ echo "ARCH=$ARCH PKGARCH=$PKGARCH ARTIFACTS=$ARTIFACTS" mkdir -p ${OUTPUT} if [ "$OS" == "linux" ]; then + # RedHat/CentOS + FILES="${ARTIFACTS}/libmsquic.${LIBEXT}.${VER_MAJOR}.${VER_MINOR}.${VER_PATCH}=/usr/${LIBDIR}/libmsquic.${LIBEXT}.${VER_MAJOR}.${VER_MINOR}.${VER_PATCH}" + FILES="${FILES} ${ARTIFACTS}/libmsquic.${LIBEXT}.${VER_MAJOR}=/usr/${LIBDIR}/libmsquic.${LIBEXT}.${VER_MAJOR}" + if [ -e "$ARTIFACTS/libmsquic.lttng.${LIBEXT}.${VER_MAJOR}.${VER_MINOR}.${VER_PATCH}" ]; then + FILES="${FILES} ${ARTIFACTS}/libmsquic.lttng.${LIBEXT}.${VER_MAJOR}.${VER_MINOR}.${VER_PATCH}=/usr/${LIBDIR}/libmsquic.lttng.${LIBEXT}.${VER_MAJOR}.${VER_MINOR}.${VER_PATCH}" + fi + if [ "$PKGARCH" == 'aarch64' ] || [ "$PKGARCH" == 'x86_64' ]; then + BITS='64bit' + fi # XDP is only validated on Ubuntu 24.04 and x64 - if [ "$XDP" == "False" ] || [[ "$ARCH" == arm* ]]; then + if [ "$XDP" == "True" ] && [[ "$ARCH" == x* ]]; then + echo "Building rpm package (XDP)" + fpm \ + --force \ + --input-type dir \ + --output-type rpm \ + --architecture ${PKGARCH} \ + --name ${NAME} \ + --provides ${NAME} \ + --depends "libcrypto.so.${TLSVERSION}()(${BITS})" \ + --depends "libnuma.so.1()(${BITS})" \ + --depends "libxdp >= 1.4.0" \ + --depends "libnl3 >= 3.0" \ + --conflicts ${CONFLICTS} \ + --version ${VER_MAJOR}.${VER_MINOR}.${VER_PATCH} \ + --description "${DESCRIPTION}" \ + --vendor "${VENDOR}" \ + --maintainer "${MAINTAINER}" \ + --package "${OUTPUT}" \ + --license MIT \ + --url https://github.com/microsoft/msquic \ + --log error \ + ${FILES} ${ARTIFACTS}/datapath_raw_xdp_kern.o=/usr/${LIBDIR}/datapath_raw_xdp_kern.o + else echo "Building rpm package" - # RedHat/CentOS - FILES="${ARTIFACTS}/libmsquic.${LIBEXT}.${VER_MAJOR}.${VER_MINOR}.${VER_PATCH}=/usr/${LIBDIR}/libmsquic.${LIBEXT}.${VER_MAJOR}.${VER_MINOR}.${VER_PATCH}" - FILES="${FILES} ${ARTIFACTS}/libmsquic.${LIBEXT}.${VER_MAJOR}=/usr/${LIBDIR}/libmsquic.${LIBEXT}.${VER_MAJOR}" - if [ -e "$ARTIFACTS/libmsquic.lttng.${LIBEXT}.${VER_MAJOR}.${VER_MINOR}.${VER_PATCH}" ]; then - FILES="${FILES} ${ARTIFACTS}/libmsquic.lttng.${LIBEXT}.${VER_MAJOR}.${VER_MINOR}.${VER_PATCH}=/usr/${LIBDIR}/libmsquic.lttng.${LIBEXT}.${VER_MAJOR}.${VER_MINOR}.${VER_PATCH}" - fi - if [ "$PKGARCH" == 'aarch64' ] || [ "$PKGARCH" == 'x86_64' ]; then - BITS='64bit' - fi fpm \ --force \ --input-type dir \ diff --git a/scripts/package-distribution.ps1 b/scripts/package-distribution.ps1 index 09039d58e5..842650a4de 100644 --- a/scripts/package-distribution.ps1 +++ b/scripts/package-distribution.ps1 @@ -8,17 +8,9 @@ param ( [Parameter(Mandatory = $false)] - [ValidateSet("ubuntu_2404", "ubuntu_2204", "ubuntu_2004", "")] - [string]$OS = "" + [switch]$Time64Distro = $false ) -$UseXdp = $false -$Time64Distro = $false -if ($OS -eq "ubuntu_2404") { - $UseXdp = $true - $Time64Distro = $true -} - Set-StrictMode -Version 'Latest' $PSDefaultParameterValues['*:ErrorAction'] = 'Stop' @@ -128,6 +120,15 @@ foreach ($Build in $AllBuilds) { $Libraries += Join-Path $ArtifactsDir "msquic.lib" } + # if datapath_raw_xdp_kern.o exists under $ArtifactsDir, $UseXdp to be true + $UseXdp = $false + if ($Platform -eq "linux") { + $XdpBin = Join-Path $ArtifactsDir "datapath_raw_xdp_kern.o" + if (Test-Path $XdpBin) { + $UseXdp = $true + } + } + # Copy items into temp folder that can be zipped in 1 command $IncludeDir = Join-Path $TempDir "include" diff --git a/scripts/run-gtest.ps1 b/scripts/run-gtest.ps1 index 4cc7740d1f..fd7a0247fb 100644 --- a/scripts/run-gtest.ps1 +++ b/scripts/run-gtest.ps1 @@ -345,6 +345,7 @@ function Start-TestExecutable([String]$Arguments, [String]$OutputDir) { } else { $pinfo.FileName = $Path $pinfo.Arguments = $Arguments + $pinfo.WorkingDirectory = $OutputDir if (Test-Administrator) { # Enable WER dump collection. New-ItemProperty -Path $WerDumpRegPath -Name DumpType -PropertyType DWord -Value 2 -Force | Out-Null @@ -381,6 +382,10 @@ function Start-TestCase([String]$Name, [int]$Trial = 1) { # Get a string of invalid chars for filenames $InvalidChars = [System.IO.Path]::GetInvalidFileNameChars() -join '' + if (!$IsWindows) { + # Add characters that Azure disallows in filenames, but aren't invalid on POSIX + $InvalidChars = $InvalidChars,'"', ":", "<", ">", "|", "*", "?", "`r", "`n" -join '' + } # Escape those chars for use in a regex and put them inside a regex set (the square brackets) $InvalidCharsToReplace = "[{0}]" -f [RegEx]::Escape($InvalidChars) $InstanceName = $Name -replace $InvalidCharsToReplace, "_" diff --git a/src/bin/CMakeLists.txt b/src/bin/CMakeLists.txt index 23768235e8..4c537a1641 100644 --- a/src/bin/CMakeLists.txt +++ b/src/bin/CMakeLists.txt @@ -250,6 +250,9 @@ elseif (CX_PLATFORM STREQUAL "darwin") PROPERTIES LINK_FLAGS "-exported_symbols_list \"${CMAKE_CURRENT_SOURCE_DIR}/darwin/exports.txt\"") endif() +include(GNUInstallDirs) +set(include_dest ${CMAKE_INSTALL_INCLUDEDIR}) + if(BUILD_SHARED_LIBS) target_include_directories(msquic PUBLIC $ @@ -263,11 +266,7 @@ else() $) endif() -set(PUBLIC_HEADERS - ../inc/msquic.h - ../inc/msquic_winuser.h - ../inc/msquic_posix.h - ../inc/quic_sal_stub.h) +file(GLOB PUBLIC_HEADERS "../inc/*.h" "../inc/*.hpp") if(BUILD_SHARED_LIBS) install(TARGETS msquic EXPORT msquic DESTINATION lib) diff --git a/src/core/binding.c b/src/core/binding.c index d8f77fdd5f..68d538f8fd 100644 --- a/src/core/binding.c +++ b/src/core/binding.c @@ -1781,7 +1781,7 @@ QuicBindingUnreachable( } _IRQL_requires_max_(DISPATCH_LEVEL) -QUIC_STATUS +void QuicBindingSend( _In_ QUIC_BINDING* Binding, _In_ const CXPLAT_ROUTE* Route, @@ -1790,8 +1790,6 @@ QuicBindingSend( _In_ uint32_t DatagramsToSend ) { - QUIC_STATUS Status; - #if QUIC_TEST_DATAPATH_HOOKS_ENABLED QUIC_TEST_DATAPATH_HOOKS* Hooks = MsQuicLib.TestDatapathHooks; if (Hooks != NULL) { @@ -1810,35 +1808,12 @@ QuicBindingSend( "[bind][%p] Test dropped packet", Binding); CxPlatSendDataFree(SendData); - Status = QUIC_STATUS_SUCCESS; } else { - Status = - CxPlatSocketSend( - Binding->Socket, - &RouteCopy, - SendData); - if (QUIC_FAILED(Status)) { - QuicTraceLogWarning( - BindingSendFailed, - "[bind][%p] Send failed, 0x%x", - Binding, - Status); - } + CxPlatSocketSend(Binding->Socket, &RouteCopy, SendData); } } else { #endif - Status = - CxPlatSocketSend( - Binding->Socket, - Route, - SendData); - if (QUIC_FAILED(Status)) { - QuicTraceLogWarning( - BindingSendFailed, - "[bind][%p] Send failed, 0x%x", - Binding, - Status); - } + CxPlatSocketSend(Binding->Socket, Route, SendData); #if QUIC_TEST_DATAPATH_HOOKS_ENABLED } #endif @@ -1846,6 +1821,4 @@ QuicBindingSend( QuicPerfCounterAdd(QUIC_PERF_COUNTER_UDP_SEND, DatagramsToSend); QuicPerfCounterAdd(QUIC_PERF_COUNTER_UDP_SEND_BYTES, BytesToSend); QuicPerfCounterIncrement(QUIC_PERF_COUNTER_UDP_SEND_CALLS); - - return Status; } diff --git a/src/core/binding.h b/src/core/binding.h index 1c5b94e42b..bdf61c3cb6 100644 --- a/src/core/binding.h +++ b/src/core/binding.h @@ -456,7 +456,7 @@ QuicBindingReleaseStatelessOperation( // the duration of the send operation. // _IRQL_requires_max_(DISPATCH_LEVEL) -QUIC_STATUS +void QuicBindingSend( _In_ QUIC_BINDING* Binding, _In_ const CXPLAT_ROUTE* Route, diff --git a/src/core/library.c b/src/core/library.c index 8b3b2f96eb..a83973b8cc 100644 --- a/src/core/library.c +++ b/src/core/library.c @@ -360,6 +360,7 @@ MsQuicLibraryInitialize( if (QUIC_FAILED(Status)) { goto Error; // Cannot log anything if platform failed to initialize. } + CxPlatWorkerPoolInit(&MsQuicLib.WorkerPool); PlatformInitialized = TRUE; CXPLAT_DBG_ASSERT(US_TO_MS(CxPlatGetTimerResolution()) + 1 <= UINT8_MAX); @@ -459,6 +460,7 @@ MsQuicLibraryInitialize( MsQuicLib.DefaultCompatibilityList = NULL; } if (PlatformInitialized) { + CxPlatWorkerPoolUninit(&MsQuicLib.WorkerPool); CxPlatUninitialize(); } } @@ -576,6 +578,7 @@ MsQuicLibraryUninitialize( LibraryUninitialized, "[ lib] Uninitialized"); + CxPlatWorkerPoolUninit(&MsQuicLib.WorkerPool); CxPlatUninitialize(); } @@ -680,6 +683,7 @@ QuicLibraryLazyInitialize( sizeof(QUIC_RX_PACKET), &DatapathCallbacks, NULL, // TcpCallbacks + &MsQuicLib.WorkerPool, MsQuicLib.ExecutionConfig, &MsQuicLib.Datapath); if (QUIC_SUCCEEDED(Status)) { @@ -1418,6 +1422,24 @@ QuicLibraryGetGlobalParam( Status = QUIC_STATUS_SUCCESS; break; + case QUIC_PARAM_GLOBAL_PLATFORM_WORKER_POOL: + + if (*BufferLength != sizeof(CXPLAT_WORKER_POOL*)) { + *BufferLength = sizeof(CXPLAT_WORKER_POOL*); + Status = QUIC_STATUS_BUFFER_TOO_SMALL; + break; + } + + if (Buffer == NULL) { + Status = QUIC_STATUS_INVALID_PARAMETER; + break; + } + + *(CXPLAT_WORKER_POOL**)Buffer = &MsQuicLib.WorkerPool; + + Status = QUIC_STATUS_SUCCESS; + break; + default: Status = QUIC_STATUS_INVALID_PARAMETER; break; @@ -1667,8 +1689,10 @@ QuicLibraryGetParam( case QUIC_PARAM_PREFIX_TLS: case QUIC_PARAM_PREFIX_TLS_SCHANNEL: - if (Connection == NULL || Connection->Crypto.TLS == NULL) { + if (Connection == NULL) { Status = QUIC_STATUS_INVALID_PARAMETER; + } else if (Connection->Crypto.TLS == NULL) { + Status = QUIC_STATUS_INVALID_STATE; } else { Status = CxPlatTlsParamGet(Connection->Crypto.TLS, Param, BufferLength, Buffer); } diff --git a/src/core/library.h b/src/core/library.h index 1dc0335b6e..930ce8111e 100644 --- a/src/core/library.h +++ b/src/core/library.h @@ -281,6 +281,11 @@ typedef struct QUIC_LIBRARY { uint64_t PerfCounterSamplesTime; int64_t PerfCounterSamples[QUIC_PERF_COUNTER_MAX]; + // + // The worker pool + // + CXPLAT_WORKER_POOL WorkerPool; + } QUIC_LIBRARY; extern QUIC_LIBRARY MsQuicLib; diff --git a/src/core/worker.c b/src/core/worker.c index 1132642953..24c687933a 100644 --- a/src/core/worker.c +++ b/src/core/worker.c @@ -99,13 +99,28 @@ QuicWorkerInitialize( #ifndef _KERNEL_MODE // Not supported on kernel mode if (ExecProfile != QUIC_EXECUTION_PROFILE_TYPE_MAX_THROUGHPUT) { Worker->IsExternal = TRUE; - CxPlatAddExecutionContext(&Worker->ExecutionContext, PartitionIndex); + CxPlatAddExecutionContext(&MsQuicLib.WorkerPool, &Worker->ExecutionContext, PartitionIndex); } else #endif // _KERNEL_MODE { - const uint16_t ThreadFlags = - ExecProfile == QUIC_EXECUTION_PROFILE_TYPE_REAL_TIME ? - CXPLAT_THREAD_FLAG_SET_AFFINITIZE : CXPLAT_THREAD_FLAG_NONE; + uint16_t ThreadFlags; + switch (ExecProfile) { + default: + case QUIC_EXECUTION_PROFILE_LOW_LATENCY: + case QUIC_EXECUTION_PROFILE_TYPE_MAX_THROUGHPUT: + ThreadFlags = CXPLAT_THREAD_FLAG_SET_IDEAL_PROC; + break; + case QUIC_EXECUTION_PROFILE_TYPE_SCAVENGER: + ThreadFlags = CXPLAT_THREAD_FLAG_NONE; + break; + case QUIC_EXECUTION_PROFILE_TYPE_REAL_TIME: + ThreadFlags = CXPLAT_THREAD_FLAG_SET_AFFINITIZE | CXPLAT_THREAD_FLAG_HIGH_PRIORITY; + break; + } + + if (MsQuicLib.ExecutionConfig && MsQuicLib.ExecutionConfig->Flags & QUIC_EXECUTION_CONFIG_FLAG_HIGH_PRIORITY) { + ThreadFlags |= CXPLAT_THREAD_FLAG_HIGH_PRIORITY; + } CXPLAT_THREAD_CONFIG ThreadConfig = { ThreadFlags, @@ -773,7 +788,7 @@ CXPLAT_THREAD_CALLBACK(QuicWorkerThread, Context) CXPLAT_EXECUTION_CONTEXT* EC = &Worker->ExecutionContext; CXPLAT_EXECUTION_STATE State = { - 0, CxPlatTimeUs64(), UINT32_MAX, 0, CxPlatCurThreadID() + 0, 0, 0, UINT32_MAX, 0, CxPlatCurThreadID() }; QuicTraceEvent( diff --git a/src/cs/QuicSimpleTest/Program.cs b/src/cs/QuicSimpleTest/Program.cs new file mode 100644 index 0000000000..8b82467bb9 --- /dev/null +++ b/src/cs/QuicSimpleTest/Program.cs @@ -0,0 +1,6 @@ +using System.Net.Quic; + +#pragma warning disable CA1416 + +Console.WriteLine($"QuicConnection.IsSupported = {QuicConnection.IsSupported}"); +return QuicConnection.IsSupported ? 0 : 1; diff --git a/src/cs/QuicSimpleTest/QuicHello.net8.0.csproj b/src/cs/QuicSimpleTest/QuicHello.net8.0.csproj new file mode 100644 index 0000000000..7d0dd78f52 --- /dev/null +++ b/src/cs/QuicSimpleTest/QuicHello.net8.0.csproj @@ -0,0 +1,9 @@ + + + Exe + net8.0 + enable + enable + true + + diff --git a/src/cs/QuicSimpleTest/QuicHello.net9.0.csproj b/src/cs/QuicSimpleTest/QuicHello.net9.0.csproj new file mode 100644 index 0000000000..736783f421 --- /dev/null +++ b/src/cs/QuicSimpleTest/QuicHello.net9.0.csproj @@ -0,0 +1,9 @@ + + + Exe + net9.0 + enable + enable + true + + diff --git a/src/cs/lib/msquic_generated.cs b/src/cs/lib/msquic_generated.cs index 59c766543d..cf1477ea76 100644 --- a/src/cs/lib/msquic_generated.cs +++ b/src/cs/lib/msquic_generated.cs @@ -216,6 +216,8 @@ internal enum QUIC_EXECUTION_CONFIG_FLAGS QTIP = 0x0001, RIO = 0x0002, XDP = 0x0004, + NO_IDEAL_PROC = 0x0008, + HIGH_PRIORITY = 0x0010, } internal unsafe partial struct QUIC_EXECUTION_CONFIG diff --git a/src/generated/linux/Tcp.cpp.clog.h b/src/generated/linux/Tcp.cpp.clog.h index b3e7495f19..8d0a54e83d 100644 --- a/src/generated/linux/Tcp.cpp.clog.h +++ b/src/generated/linux/Tcp.cpp.clog.h @@ -115,16 +115,18 @@ tracepoint(CLOG_TCP_CPP, PerfTcpReceiveCallback , arg2);\ /*---------------------------------------------------------- // Decoder Ring for PerfTcpSendCompleteCallback -// [perf][tcp][%p] SendComplete callback +// [perf][tcp][%p] SendComplete callback, %u // QuicTraceLogVerbose( PerfTcpSendCompleteCallback, - "[perf][tcp][%p] SendComplete callback", - This); + "[perf][tcp][%p] SendComplete callback, %u", + This, + (uint32_t)Status); // arg2 = arg2 = This = arg2 +// arg3 = arg3 = (uint32_t)Status = arg3 ----------------------------------------------------------*/ -#ifndef _clog_3_ARGS_TRACE_PerfTcpSendCompleteCallback -#define _clog_3_ARGS_TRACE_PerfTcpSendCompleteCallback(uniqueId, encoded_arg_string, arg2)\ -tracepoint(CLOG_TCP_CPP, PerfTcpSendCompleteCallback , arg2);\ +#ifndef _clog_4_ARGS_TRACE_PerfTcpSendCompleteCallback +#define _clog_4_ARGS_TRACE_PerfTcpSendCompleteCallback(uniqueId, encoded_arg_string, arg2, arg3)\ +tracepoint(CLOG_TCP_CPP, PerfTcpSendCompleteCallback , arg2, arg3);\ #endif diff --git a/src/generated/linux/Tcp.cpp.clog.h.lttng.h b/src/generated/linux/Tcp.cpp.clog.h.lttng.h index 711615bac7..40b605b9b7 100644 --- a/src/generated/linux/Tcp.cpp.clog.h.lttng.h +++ b/src/generated/linux/Tcp.cpp.clog.h.lttng.h @@ -102,18 +102,22 @@ TRACEPOINT_EVENT(CLOG_TCP_CPP, PerfTcpReceiveCallback, /*---------------------------------------------------------- // Decoder Ring for PerfTcpSendCompleteCallback -// [perf][tcp][%p] SendComplete callback +// [perf][tcp][%p] SendComplete callback, %u // QuicTraceLogVerbose( PerfTcpSendCompleteCallback, - "[perf][tcp][%p] SendComplete callback", - This); + "[perf][tcp][%p] SendComplete callback, %u", + This, + (uint32_t)Status); // arg2 = arg2 = This = arg2 +// arg3 = arg3 = (uint32_t)Status = arg3 ----------------------------------------------------------*/ TRACEPOINT_EVENT(CLOG_TCP_CPP, PerfTcpSendCompleteCallback, TP_ARGS( - const void *, arg2), + const void *, arg2, + unsigned int, arg3), TP_FIELDS( ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) + ctf_integer(unsigned int, arg3, arg3) ) ) diff --git a/src/generated/linux/binding.c.clog.h b/src/generated/linux/binding.c.clog.h index f6212114fe..01f0aab2f3 100644 --- a/src/generated/linux/binding.c.clog.h +++ b/src/generated/linux/binding.c.clog.h @@ -48,26 +48,6 @@ tracepoint(CLOG_BINDING_C, BindingListenerAlreadyRegistered , arg2, arg3);\ -/*---------------------------------------------------------- -// Decoder Ring for BindingSendFailed -// [bind][%p] Send failed, 0x%x -// QuicTraceLogWarning( - BindingSendFailed, - "[bind][%p] Send failed, 0x%x", - Binding, - Status); -// arg2 = arg2 = Binding = arg2 -// arg3 = arg3 = Status = arg3 -----------------------------------------------------------*/ -#ifndef _clog_4_ARGS_TRACE_BindingSendFailed -#define _clog_4_ARGS_TRACE_BindingSendFailed(uniqueId, encoded_arg_string, arg2, arg3)\ -tracepoint(CLOG_BINDING_C, BindingSendFailed , arg2, arg3);\ - -#endif - - - - /*---------------------------------------------------------- // Decoder Ring for PacketTxVersionNegotiation // [S][TX][-] VN diff --git a/src/generated/linux/binding.c.clog.h.lttng.h b/src/generated/linux/binding.c.clog.h.lttng.h index 7392a89c6e..a9ef610a9b 100644 --- a/src/generated/linux/binding.c.clog.h.lttng.h +++ b/src/generated/linux/binding.c.clog.h.lttng.h @@ -23,29 +23,6 @@ TRACEPOINT_EVENT(CLOG_BINDING_C, BindingListenerAlreadyRegistered, -/*---------------------------------------------------------- -// Decoder Ring for BindingSendFailed -// [bind][%p] Send failed, 0x%x -// QuicTraceLogWarning( - BindingSendFailed, - "[bind][%p] Send failed, 0x%x", - Binding, - Status); -// arg2 = arg2 = Binding = arg2 -// arg3 = arg3 = Status = arg3 -----------------------------------------------------------*/ -TRACEPOINT_EVENT(CLOG_BINDING_C, BindingSendFailed, - TP_ARGS( - const void *, arg2, - unsigned int, arg3), - TP_FIELDS( - ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) - ctf_integer(unsigned int, arg3, arg3) - ) -) - - - /*---------------------------------------------------------- // Decoder Ring for PacketTxVersionNegotiation // [S][TX][-] VN diff --git a/src/generated/linux/platform_winuser.c.clog.h b/src/generated/linux/platform_winuser.c.clog.h index 3c439fd3ab..614949d980 100644 --- a/src/generated/linux/platform_winuser.c.clog.h +++ b/src/generated/linux/platform_winuser.c.clog.h @@ -82,11 +82,11 @@ tracepoint(CLOG_PLATFORM_WINUSER_C, WindowsUserProcessorStateV3 , arg2, arg3, ar /*---------------------------------------------------------- -// Decoder Ring for ProcessorInfoV2 -// [ dll] Proc[%u] Group[%hu] Index[%u] Active=%hhu +// Decoder Ring for ProcessorInfoV3 +// [ dll] Proc[%u] Group[%hu] Index[%hhu] Active=%hhu // QuicTraceLogInfo( - ProcessorInfoV2, - "[ dll] Proc[%u] Group[%hu] Index[%u] Active=%hhu", + ProcessorInfoV3, + "[ dll] Proc[%u] Group[%hu] Index[%hhu] Active=%hhu", Proc, (uint16_t)Group, CxPlatProcessorInfo[Proc].Index, @@ -96,9 +96,9 @@ tracepoint(CLOG_PLATFORM_WINUSER_C, WindowsUserProcessorStateV3 , arg2, arg3, ar // arg4 = arg4 = CxPlatProcessorInfo[Proc].Index = arg4 // arg5 = arg5 = (uint8_t)!!(CxPlatProcessorGroupInfo[Group].Mask & (1ULL << CxPlatProcessorInfo[Proc].Index)) = arg5 ----------------------------------------------------------*/ -#ifndef _clog_6_ARGS_TRACE_ProcessorInfoV2 -#define _clog_6_ARGS_TRACE_ProcessorInfoV2(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg5)\ -tracepoint(CLOG_PLATFORM_WINUSER_C, ProcessorInfoV2 , arg2, arg3, arg4, arg5);\ +#ifndef _clog_6_ARGS_TRACE_ProcessorInfoV3 +#define _clog_6_ARGS_TRACE_ProcessorInfoV3(uniqueId, encoded_arg_string, arg2, arg3, arg4, arg5)\ +tracepoint(CLOG_PLATFORM_WINUSER_C, ProcessorInfoV3 , arg2, arg3, arg4, arg5);\ #endif diff --git a/src/generated/linux/platform_winuser.c.clog.h.lttng.h b/src/generated/linux/platform_winuser.c.clog.h.lttng.h index 0249e83963..211ade1a7b 100644 --- a/src/generated/linux/platform_winuser.c.clog.h.lttng.h +++ b/src/generated/linux/platform_winuser.c.clog.h.lttng.h @@ -65,11 +65,11 @@ TRACEPOINT_EVENT(CLOG_PLATFORM_WINUSER_C, WindowsUserProcessorStateV3, /*---------------------------------------------------------- -// Decoder Ring for ProcessorInfoV2 -// [ dll] Proc[%u] Group[%hu] Index[%u] Active=%hhu +// Decoder Ring for ProcessorInfoV3 +// [ dll] Proc[%u] Group[%hu] Index[%hhu] Active=%hhu // QuicTraceLogInfo( - ProcessorInfoV2, - "[ dll] Proc[%u] Group[%hu] Index[%u] Active=%hhu", + ProcessorInfoV3, + "[ dll] Proc[%u] Group[%hu] Index[%hhu] Active=%hhu", Proc, (uint16_t)Group, CxPlatProcessorInfo[Proc].Index, @@ -79,16 +79,16 @@ TRACEPOINT_EVENT(CLOG_PLATFORM_WINUSER_C, WindowsUserProcessorStateV3, // arg4 = arg4 = CxPlatProcessorInfo[Proc].Index = arg4 // arg5 = arg5 = (uint8_t)!!(CxPlatProcessorGroupInfo[Group].Mask & (1ULL << CxPlatProcessorInfo[Proc].Index)) = arg5 ----------------------------------------------------------*/ -TRACEPOINT_EVENT(CLOG_PLATFORM_WINUSER_C, ProcessorInfoV2, +TRACEPOINT_EVENT(CLOG_PLATFORM_WINUSER_C, ProcessorInfoV3, TP_ARGS( unsigned int, arg2, unsigned short, arg3, - unsigned int, arg4, + unsigned char, arg4, unsigned char, arg5), TP_FIELDS( ctf_integer(unsigned int, arg2, arg2) ctf_integer(unsigned short, arg3, arg3) - ctf_integer(unsigned int, arg4, arg4) + ctf_integer(unsigned char, arg4, arg4) ctf_integer(unsigned char, arg5, arg5) ) ) diff --git a/src/generated/linux/platform_worker.c.clog.h b/src/generated/linux/platform_worker.c.clog.h index e2141b3aa0..533ae2a751 100644 --- a/src/generated/linux/platform_worker.c.clog.h +++ b/src/generated/linux/platform_worker.c.clog.h @@ -18,6 +18,10 @@ #define _clog_MACRO_QuicTraceLogInfo 1 #define QuicTraceLogInfo(a, ...) _clog_CAT(_clog_ARGN_SELECTOR(__VA_ARGS__), _clog_CAT(_,a(#a, __VA_ARGS__))) #endif +#ifndef _clog_MACRO_QuicTraceLogVerbose +#define _clog_MACRO_QuicTraceLogVerbose 1 +#define QuicTraceLogVerbose(a, ...) _clog_CAT(_clog_ARGN_SELECTOR(__VA_ARGS__), _clog_CAT(_,a(#a, __VA_ARGS__))) +#endif #ifndef _clog_MACRO_QuicTraceEvent #define _clog_MACRO_QuicTraceEvent 1 #define QuicTraceEvent(a, ...) _clog_CAT(_clog_ARGN_SELECTOR(__VA_ARGS__), _clog_CAT(_,a(#a, __VA_ARGS__))) @@ -61,6 +65,24 @@ tracepoint(CLOG_PLATFORM_WORKER_C, PlatformWorkerThreadStop , arg2);\ +/*---------------------------------------------------------- +// Decoder Ring for PlatformWorkerProcessPools +// [ lib][%p] Processing pools +// QuicTraceLogVerbose( + PlatformWorkerProcessPools, + "[ lib][%p] Processing pools", + Worker); +// arg2 = arg2 = Worker = arg2 +----------------------------------------------------------*/ +#ifndef _clog_3_ARGS_TRACE_PlatformWorkerProcessPools +#define _clog_3_ARGS_TRACE_PlatformWorkerProcessPools(uniqueId, encoded_arg_string, arg2)\ +tracepoint(CLOG_PLATFORM_WORKER_C, PlatformWorkerProcessPools , arg2);\ + +#endif + + + + /*---------------------------------------------------------- // Decoder Ring for AllocFailure // Allocation of '%s' failed. (%llu bytes) diff --git a/src/generated/linux/platform_worker.c.clog.h.lttng.h b/src/generated/linux/platform_worker.c.clog.h.lttng.h index 7f82dccbd4..db19ead56e 100644 --- a/src/generated/linux/platform_worker.c.clog.h.lttng.h +++ b/src/generated/linux/platform_worker.c.clog.h.lttng.h @@ -39,6 +39,25 @@ TRACEPOINT_EVENT(CLOG_PLATFORM_WORKER_C, PlatformWorkerThreadStop, +/*---------------------------------------------------------- +// Decoder Ring for PlatformWorkerProcessPools +// [ lib][%p] Processing pools +// QuicTraceLogVerbose( + PlatformWorkerProcessPools, + "[ lib][%p] Processing pools", + Worker); +// arg2 = arg2 = Worker = arg2 +----------------------------------------------------------*/ +TRACEPOINT_EVENT(CLOG_PLATFORM_WORKER_C, PlatformWorkerProcessPools, + TP_ARGS( + const void *, arg2), + TP_FIELDS( + ctf_integer_hex(uint64_t, arg2, (uint64_t)arg2) + ) +) + + + /*---------------------------------------------------------- // Decoder Ring for AllocFailure // Allocation of '%s' failed. (%llu bytes) diff --git a/src/inc/msquic.h b/src/inc/msquic.h index 0f7649ee82..d9c25b8933 100644 --- a/src/inc/msquic.h +++ b/src/inc/msquic.h @@ -270,6 +270,8 @@ typedef enum QUIC_EXECUTION_CONFIG_FLAGS { QUIC_EXECUTION_CONFIG_FLAG_QTIP = 0x0001, QUIC_EXECUTION_CONFIG_FLAG_RIO = 0x0002, QUIC_EXECUTION_CONFIG_FLAG_XDP = 0x0004, + QUIC_EXECUTION_CONFIG_FLAG_NO_IDEAL_PROC = 0x0008, + QUIC_EXECUTION_CONFIG_FLAG_HIGH_PRIORITY = 0x0010, #endif } QUIC_EXECUTION_CONFIG_FLAGS; diff --git a/src/inc/msquichelper.h b/src/inc/msquichelper.h index a3837bec4a..4572ddbd3e 100644 --- a/src/inc/msquichelper.h +++ b/src/inc/msquichelper.h @@ -568,9 +568,352 @@ FreeServerConfiguration( MsQuicTable->ConfigurationClose(Configuration); } +#ifdef _KERNEL_MODE inline void -WriteSslKeyLogFile( +WriteSslKeyLogFileKernelMode( + _In_z_ const char* FileName, + _In_ QUIC_TLS_SECRETS& TlsSecrets + ) +{ + WCHAR ConvertedFileName[MAX_PATH + 1] = {0}; + char ClientRandomBuffer[(2 * sizeof(QUIC_TLS_SECRETS::ClientRandom)) + 1] = {0}; + char TempHexBuffer[(2 * QUIC_TLS_SECRETS_MAX_SECRET_LEN) + 1] = {0}; + char TempLogBuffer[sizeof(ClientRandomBuffer) + sizeof(TempHexBuffer) + 32 + 3 + 1] = {0}; + UNICODE_STRING FileNameString = {0}; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + HANDLE Handle; + size_t RemainingLengthBytes = 0; + NTSTATUS Status; + ULONG StringLengthBytes = 0; + + size_t FileNameLength = strnlen_s(FileName, MAX_PATH + 1); + if (FileNameLength == MAX_PATH + 1) { + goto Error; + } + FileNameLength++; + + Status = + RtlUTF8ToUnicodeN( + ConvertedFileName, + sizeof(ConvertedFileName), + &StringLengthBytes, + FileName, + (ULONG) FileNameLength); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Convert string to unicode"); + goto Error; + } + + FileNameString.Buffer = ConvertedFileName; + FileNameString.Length = (USHORT)StringLengthBytes - sizeof(WCHAR); + FileNameString.MaximumLength = (USHORT)sizeof(ConvertedFileName); + + InitializeObjectAttributes( + &ObjectAttributes, + &FileNameString, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL); + + Status = + ZwCreateFile( + &Handle, + FILE_APPEND_DATA | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + 0, + FILE_OPEN_IF, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, + NULL, + 0); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Open sslkeylogfile for append"); + goto Error; + } + + if (IoStatusBlock.Information == FILE_CREATED) { + CHAR Header[] = "# TLS 1.3 secrets log file, generated by quicinterop\n"; + Status = + ZwWriteFile( + Handle, + NULL, + NULL, + NULL, + &IoStatusBlock, + Header, + sizeof(Header) - 1, + NULL, + NULL); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Write header to sslkeylogfile"); + goto WriteError; + } + } + + if (TlsSecrets.IsSet.ClientRandom) { + EncodeHexBuffer( + TlsSecrets.ClientRandom, + (uint8_t)sizeof(TlsSecrets.ClientRandom), + ClientRandomBuffer); + } + + if (TlsSecrets.IsSet.ClientEarlyTrafficSecret) { + EncodeHexBuffer( + TlsSecrets.ClientEarlyTrafficSecret, + TlsSecrets.SecretLength, + TempHexBuffer); + + Status = + RtlStringCbPrintfExA( + TempLogBuffer, + sizeof(TempLogBuffer), + NULL, + &RemainingLengthBytes, + 0, + "CLIENT_EARLY_TRAFFIC_SECRET %s %s\n", + ClientRandomBuffer, + TempHexBuffer); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Format CLIENT_EARLY_TRAFFIC_SECRET"); + goto WriteError; + } + + Status = + ZwWriteFile( + Handle, + NULL, + NULL, + NULL, + &IoStatusBlock, + TempLogBuffer, + (ULONG)(sizeof(TempLogBuffer) - RemainingLengthBytes), + NULL, + NULL); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Write CLIENT_EARLY_TRAFFIC_SECRET"); + goto WriteError; + } + } + + if (TlsSecrets.IsSet.ClientHandshakeTrafficSecret) { + EncodeHexBuffer( + TlsSecrets.ClientHandshakeTrafficSecret, + TlsSecrets.SecretLength, + TempHexBuffer); + + Status = + RtlStringCbPrintfExA( + TempLogBuffer, + sizeof(TempLogBuffer), + NULL, + &RemainingLengthBytes, + 0, + "CLIENT_HANDSHAKE_TRAFFIC_SECRET %s %s\n", + ClientRandomBuffer, + TempHexBuffer); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Format CLIENT_HANDSHAKE_TRAFFIC_SECRET"); + goto WriteError; + } + + Status = + ZwWriteFile( + Handle, + NULL, + NULL, + NULL, + &IoStatusBlock, + TempLogBuffer, + (ULONG)(sizeof(TempLogBuffer) - RemainingLengthBytes), + NULL, + NULL); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Write CLIENT_HANDSHAKE_TRAFFIC_SECRET"); + goto WriteError; + } + } + + if (TlsSecrets.IsSet.ServerHandshakeTrafficSecret) { + EncodeHexBuffer( + TlsSecrets.ServerHandshakeTrafficSecret, + TlsSecrets.SecretLength, + TempHexBuffer); + + Status = + RtlStringCbPrintfExA( + TempLogBuffer, + sizeof(TempLogBuffer), + NULL, + &RemainingLengthBytes, + 0, + "SERVER_HANDSHAKE_TRAFFIC_SECRET %s %s\n", + ClientRandomBuffer, + TempHexBuffer); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Format SERVER_HANDSHAKE_TRAFFIC_SECRET"); + goto WriteError; + } + + Status = + ZwWriteFile( + Handle, + NULL, + NULL, + NULL, + &IoStatusBlock, + TempLogBuffer, + (ULONG)(sizeof(TempLogBuffer) - RemainingLengthBytes), + NULL, + NULL); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Write SERVER_HANDSHAKE_TRAFFIC_SECRET"); + goto WriteError; + } + } + + if (TlsSecrets.IsSet.ClientTrafficSecret0) { + EncodeHexBuffer( + TlsSecrets.ClientTrafficSecret0, + TlsSecrets.SecretLength, + TempHexBuffer); + + Status = + RtlStringCbPrintfExA( + TempLogBuffer, + sizeof(TempLogBuffer), + NULL, + &RemainingLengthBytes, + 0, + "CLIENT_TRAFFIC_SECRET_0 %s %s\n", + ClientRandomBuffer, + TempHexBuffer); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Format CLIENT_TRAFFIC_SECRET_0"); + goto WriteError; + } + + Status = + ZwWriteFile( + Handle, + NULL, + NULL, + NULL, + &IoStatusBlock, + TempLogBuffer, + (ULONG)(sizeof(TempLogBuffer) - RemainingLengthBytes), + NULL, + NULL); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Write CLIENT_TRAFFIC_SECRET_0"); + goto WriteError; + } + } + + if (TlsSecrets.IsSet.ServerTrafficSecret0) { + EncodeHexBuffer( + TlsSecrets.ServerTrafficSecret0, + TlsSecrets.SecretLength, + TempHexBuffer); + + Status = + RtlStringCbPrintfExA( + TempLogBuffer, + sizeof(TempLogBuffer), + NULL, + &RemainingLengthBytes, + 0, + "SERVER_TRAFFIC_SECRET_0 %s %s\n", + ClientRandomBuffer, + TempHexBuffer); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Format SERVER_TRAFFIC_SECRET_0"); + goto WriteError; + } + + Status = + ZwWriteFile( + Handle, + NULL, + NULL, + NULL, + &IoStatusBlock, + TempLogBuffer, + (ULONG)(sizeof(TempLogBuffer) - RemainingLengthBytes), + NULL, + NULL); + if (!NT_SUCCESS(Status)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Status, + "Write SERVER_TRAFFIC_SECRET_0"); + goto WriteError; + } + } + +WriteError: + ZwClose(Handle); + +Error: + return; +} +#endif + +inline +void +WriteSslKeyLogFileUserMode( _In_z_ const char* FileName, _In_ QUIC_TLS_SECRETS& TlsSecrets ) @@ -662,4 +1005,19 @@ WriteSslKeyLogFile( fclose(File); } + +inline +void +WriteSslKeyLogFile( + _In_z_ const char* FileName, + _In_ QUIC_TLS_SECRETS& TlsSecrets + ) +{ +#ifdef _KERNEL_MODE + WriteSslKeyLogFileKernelMode(FileName, TlsSecrets); +#else + WriteSslKeyLogFileUserMode(FileName, TlsSecrets); +#endif +} + #endif // defined(__cplusplus) diff --git a/src/inc/msquicp.h b/src/inc/msquicp.h index 55f5b2b420..138a880c74 100644 --- a/src/inc/msquicp.h +++ b/src/inc/msquicp.h @@ -116,6 +116,7 @@ typedef struct QUIC_PRIVATE_TRANSPORT_PARAMETER { #endif #define QUIC_PARAM_GLOBAL_IN_USE 0x81000004 // BOOLEAN #define QUIC_PARAM_GLOBAL_DATAPATH_FEATURES 0x81000005 // uint32_t +#define QUIC_PARAM_GLOBAL_PLATFORM_WORKER_POOL 0x81000006 // CXPLAT_WORKER_POOL* // // The different private parameters for Configuration. diff --git a/src/inc/quic_datapath.h b/src/inc/quic_datapath.h index 76e1b456ed..a5dd6a335c 100644 --- a/src/inc/quic_datapath.h +++ b/src/inc/quic_datapath.h @@ -282,11 +282,14 @@ typedef struct CXPLAT_QEO_CONNECTION { // // Function pointer type for datapath TCP accept callbacks. +// Any QUIC_FAILED status will reject the connection. +// Do not call CxPlatSocketDelete from this callback, it will +// crash. // typedef _IRQL_requires_max_(DISPATCH_LEVEL) _Function_class_(CXPLAT_DATAPATH_ACCEPT_CALLBACK) -void +QUIC_STATUS (CXPLAT_DATAPATH_ACCEPT_CALLBACK)( _In_ CXPLAT_SOCKET* ListenerSocket, _In_ void* ListenerContext, @@ -404,6 +407,7 @@ CxPlatDataPathInitialize( _In_ uint32_t ClientRecvContextLength, _In_opt_ const CXPLAT_UDP_DATAPATH_CALLBACKS* UdpCallbacks, _In_opt_ const CXPLAT_TCP_DATAPATH_CALLBACKS* TcpCallbacks, + _In_ CXPLAT_WORKER_POOL* WorkerPool, _In_opt_ QUIC_EXECUTION_CONFIG* Config, _Out_ CXPLAT_DATAPATH** NewDatapath ); @@ -636,6 +640,15 @@ CxPlatSocketGetRemoteAddress( _Out_ QUIC_ADDR* Address ); +// +// Queries a raw socket availability. +// +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +CxPlatSocketRawSocketAvailable( + _In_ CXPLAT_SOCKET* Socket + ); + // // Called to return a chain of datagrams received from the registered receive // callback. @@ -713,7 +726,7 @@ CxPlatSendDataIsFull( // Sends the data over the socket. // _IRQL_requires_max_(DISPATCH_LEVEL) -QUIC_STATUS +void CxPlatSocketSend( _In_ CXPLAT_SOCKET* Socket, _In_ const CXPLAT_ROUTE* Route, diff --git a/src/inc/quic_platform.h b/src/inc/quic_platform.h index 5de7c3693d..ceaa6cdcd8 100644 --- a/src/inc/quic_platform.h +++ b/src/inc/quic_platform.h @@ -19,6 +19,10 @@ Supported Environments: #include +#if defined(__cplusplus) +extern "C" { +#endif + #define IS_POWER_OF_TWO(x) (((x) != 0) && (((x) & ((x) - 1)) == 0)) #define CXPLAT_MAX(a,b) (((a) > (b)) ? (a) : (b)) @@ -417,6 +421,36 @@ CxPlatGetAllocFailDenominator( #define CxPlatIsRandomMemoryFailureEnabled() (FALSE) #endif +// +// Worker pool API used for driving execution contexts +// + +typedef struct CXPLAT_WORKER CXPLAT_WORKER; + +typedef struct CXPLAT_WORKER_POOL { + + CXPLAT_WORKER* Workers; + CXPLAT_LOCK WorkerLock; + CXPLAT_RUNDOWN_REF Rundown; + uint32_t WorkerCount; + +} CXPLAT_WORKER_POOL; + +#ifdef _KERNEL_MODE // Not supported on kernel mode +#define CxPlatWorkerPoolInit(WorkerPool) UNREFERENCED_PARAMETER(WorkerPool) +#define CxPlatWorkerPoolUninit(WorkerPool) UNREFERENCED_PARAMETER(WorkerPool) +#else +void +CxPlatWorkerPoolInit( + _In_ CXPLAT_WORKER_POOL* WorkerPool + ); + +void +CxPlatWorkerPoolUninit( + _In_ CXPLAT_WORKER_POOL* WorkerPool + ); +#endif + // // General purpose execution context abstraction layer. Used for driving worker // loops. @@ -427,13 +461,40 @@ typedef struct QUIC_EXECUTION_CONFIG QUIC_EXECUTION_CONFIG; typedef struct CXPLAT_EXECUTION_CONTEXT CXPLAT_EXECUTION_CONTEXT; typedef struct CXPLAT_EXECUTION_STATE { - uint64_t TimeNow; // in microseconds - uint64_t LastWorkTime; // in microseconds + uint64_t TimeNow; // in microseconds + uint64_t LastWorkTime; // in microseconds + uint64_t LastPoolProcessTime; // in microseconds uint32_t WaitTime; uint32_t NoWorkCount; CXPLAT_THREAD_ID ThreadID; } CXPLAT_EXECUTION_STATE; +#ifndef _KERNEL_MODE // Not supported on kernel mode + +// +// Supports more dynamic operations, but must be submitted to the platform worker +// to manage. +// +typedef struct CXPLAT_POOL_EX { + CXPLAT_POOL Base; + CXPLAT_LIST_ENTRY Link; + void* Owner; +} CXPLAT_POOL_EX; + +void +CxPlatAddDynamicPoolAllocator( + _In_ CXPLAT_WORKER_POOL* WorkerPool, + _Inout_ CXPLAT_POOL_EX* Pool, + _In_ uint16_t Index // Into the execution config processor array + ); + +void +CxPlatRemoveDynamicPoolAllocator( + _Inout_ CXPLAT_POOL_EX* Pool + ); + +#endif + // // Returns FALSE when it's time to cleanup. // @@ -464,11 +525,12 @@ typedef struct CXPLAT_EXECUTION_CONTEXT { } CXPLAT_EXECUTION_CONTEXT; #ifdef _KERNEL_MODE // Not supported on kernel mode -#define CxPlatAddExecutionContext(Context, IdealProcessor) CXPLAT_FRE_ASSERT(FALSE) +#define CxPlatAddExecutionContext(WorkerPool, Context, IdealProcessor) CXPLAT_FRE_ASSERT(FALSE) #define CxPlatWakeExecutionContext(Context) CXPLAT_FRE_ASSERT(FALSE) #else void CxPlatAddExecutionContext( + _In_ CXPLAT_WORKER_POOL* WorkerPool, _Inout_ CXPLAT_EXECUTION_CONTEXT* Context, _In_ uint16_t Index // Into the execution config processor array ); @@ -592,3 +654,7 @@ CxPlatFreeTestCert( #endif #endif // QUIC_TEST_APIS + +#if defined(__cplusplus) +} +#endif diff --git a/src/inc/quic_platform_posix.h b/src/inc/quic_platform_posix.h index 7d0eaf125c..afa718ebb1 100644 --- a/src/inc/quic_platform_posix.h +++ b/src/inc/quic_platform_posix.h @@ -478,7 +478,11 @@ typedef struct CXPLAT_POOL { } CXPLAT_POOL; +#ifndef DISABLE_CXPLAT_POOL #define CXPLAT_POOL_MAXIMUM_DEPTH 256 // Copied from EX_MAXIMUM_LOOKASIDE_DEPTH_BASE +#else +#define CXPLAT_POOL_MAXIMUM_DEPTH 0 // TODO - Optimize this scenario better +#endif #if DEBUG typedef struct CXPLAT_POOL_ENTRY { @@ -585,6 +589,26 @@ CxPlatPoolFree( } } +inline +BOOLEAN +CxPlatPoolPrune( + _Inout_ CXPLAT_POOL* Pool + ) +{ + CxPlatLockAcquire(&Pool->Lock); + void* Entry = CxPlatListPopEntry(&Pool->ListHead); + if (Entry != NULL) { + CXPLAT_FRE_ASSERT(Pool->ListDepth > 0); + Pool->ListDepth--; + } + CxPlatLockRelease(&Pool->Lock); + if (Entry == NULL) { + return FALSE; + } + CxPlatFree(Entry, Pool->Tag); + return TRUE; +} + // // Reference Count Interface // @@ -1125,7 +1149,7 @@ CxPlatCqeUserData( #include typedef int CXPLAT_EVENTQ; -#define CXPLAT_SQE int +#define CXPLAT_SQE uintptr_t #define CXPLAT_SQE_DEFAULT 0 typedef struct kevent CXPLAT_CQE; @@ -1193,7 +1217,7 @@ CxPlatEventQReturn( #define CXPLAT_SQE_INIT 1 -extern long CxPlatCurrentSqe; +extern uintptr_t CxPlatCurrentSqe; inline BOOLEAN @@ -1205,7 +1229,7 @@ CxPlatSqeInitialize( { UNREFERENCED_PARAMETER(queue); UNREFERENCED_PARAMETER(user_data); - *sqe = (CXPLAT_SQE)InterlockedIncrement(&CxPlatCurrentSqe); + *sqe = __sync_add_and_fetch(&CxPlatCurrentSqe, 1); return TRUE; } diff --git a/src/inc/quic_platform_winuser.h b/src/inc/quic_platform_winuser.h index 9c3f418cc5..8295c64f43 100644 --- a/src/inc/quic_platform_winuser.h +++ b/src/inc/quic_platform_winuser.h @@ -319,7 +319,7 @@ typedef struct CXPLAT_POOL { #define CXPLAT_POOL_MAXIMUM_DEPTH 0x4000 // 16384 #define CXPLAT_POOL_DEFAULT_MAX_DEPTH 256 // Copied from EX_MAXIMUM_LOOKASIDE_DEPTH_BASE #else -#define CXPLAT_POOL_MAXIMUM_DEPTH 0 +#define CXPLAT_POOL_MAXIMUM_DEPTH 0 // TODO - Optimize this scenario better #define CXPLAT_POOL_DEFAULT_MAX_DEPTH 0 #endif @@ -465,6 +465,20 @@ CxPlatPoolFree( } } +inline +BOOLEAN +CxPlatPoolPrune( + _Inout_ CXPLAT_POOL* Pool + ) +{ + void* Entry = InterlockedPopEntrySList(&Pool->ListHead); + if (Entry == NULL) { + return FALSE; + } + Pool->Free(Entry, Pool->Tag, Pool); + return TRUE; +} + #define CxPlatZeroMemory RtlZeroMemory #define CxPlatCopyMemory RtlCopyMemory #define CxPlatMoveMemory RtlMoveMemory @@ -771,7 +785,7 @@ CxPlatEventQDequeue( ) { ULONG out_count = 0; - if (!GetQueuedCompletionStatusEx(*queue, events, count, &out_count, wait_time, FALSE)) return FALSE; + if (!GetQueuedCompletionStatusEx(*queue, events, count, &out_count, wait_time, FALSE)) return 0; CXPLAT_DBG_ASSERT(out_count != 0); CXPLAT_DBG_ASSERT(events[0].lpOverlapped != NULL || out_count == 1); #if DEBUG @@ -987,10 +1001,13 @@ CxPlatTimeAtOrBefore32( // typedef struct CXPLAT_PROCESSOR_INFO { - uint32_t Index; // Index in the current group uint16_t Group; // The group number this processor is a part of + uint8_t Index; // Index in the current group + uint8_t PADDING; // Here to align with PROCESSOR_NUMBER struct } CXPLAT_PROCESSOR_INFO; +CXPLAT_STATIC_ASSERT(sizeof(CXPLAT_PROCESSOR_INFO) == sizeof(PROCESSOR_NUMBER), "Size check"); + typedef struct CXPLAT_PROCESSOR_GROUP_INFO { KAFFINITY Mask; // Bit mask of active processors in the group uint32_t Count; // Count of active processors in the group @@ -1094,90 +1111,11 @@ CXPLAT_THREAD_CALLBACK(CxPlatThreadCustomStart, CustomContext); // CXPLAT_THREAD #endif // CXPLAT_USE_CUSTOM_THREAD_CONTEXT -inline QUIC_STATUS CxPlatThreadCreate( _In_ CXPLAT_THREAD_CONFIG* Config, _Out_ CXPLAT_THREAD* Thread - ) -{ -#ifdef CXPLAT_USE_CUSTOM_THREAD_CONTEXT - CXPLAT_THREAD_CUSTOM_CONTEXT* CustomContext = - CXPLAT_ALLOC_NONPAGED(sizeof(CXPLAT_THREAD_CUSTOM_CONTEXT), QUIC_POOL_CUSTOM_THREAD); - if (CustomContext == NULL) { - QuicTraceEvent( - AllocFailure, - "Allocation of '%s' failed. (%llu bytes)", - "Custom thread context", - sizeof(CXPLAT_THREAD_CUSTOM_CONTEXT)); - return QUIC_STATUS_OUT_OF_MEMORY; - } - CustomContext->Callback = Config->Callback; - CustomContext->Context = Config->Context; - *Thread = - CreateThread( - NULL, - 0, - CxPlatThreadCustomStart, - CustomContext, - 0, - NULL); - if (*Thread == NULL) { - CXPLAT_FREE(CustomContext, QUIC_POOL_CUSTOM_THREAD); - return GetLastError(); - } -#else // CXPLAT_USE_CUSTOM_THREAD_CONTEXT - *Thread = - CreateThread( - NULL, - 0, - Config->Callback, - Config->Context, - 0, - NULL); - if (*Thread == NULL) { - return GetLastError(); - } -#endif // CXPLAT_USE_CUSTOM_THREAD_CONTEXT - CXPLAT_DBG_ASSERT(Config->IdealProcessor < CxPlatProcCount()); - const CXPLAT_PROCESSOR_INFO* ProcInfo = &CxPlatProcessorInfo[Config->IdealProcessor]; - GROUP_AFFINITY Group = {0}; - if (Config->Flags & CXPLAT_THREAD_FLAG_SET_AFFINITIZE) { - Group.Mask = (KAFFINITY)(1ull << ProcInfo->Index); // Fixed processor - } else { - Group.Mask = CxPlatProcessorGroupInfo[ProcInfo->Group].Mask; - } - Group.Group = ProcInfo->Group; - SetThreadGroupAffinity(*Thread, &Group, NULL); - if (Config->Flags & CXPLAT_THREAD_FLAG_SET_IDEAL_PROC) { - SetThreadIdealProcessor(*Thread, ProcInfo->Index); - } - if (Config->Flags & CXPLAT_THREAD_FLAG_HIGH_PRIORITY) { - SetThreadPriority(*Thread, THREAD_PRIORITY_HIGHEST); - } - if (Config->Name) { - WCHAR WideName[64] = L""; - size_t WideNameLength; - mbstowcs_s( - &WideNameLength, - WideName, - ARRAYSIZE(WideName) - 1, - Config->Name, - _TRUNCATE); -#if defined(QUIC_RESTRICTED_BUILD) - SetThreadDescription(*Thread, WideName); -#else - THREAD_NAME_INFORMATION_PRIVATE ThreadNameInfo; - RtlInitUnicodeString(&ThreadNameInfo.ThreadName, WideName); - NtSetInformationThread( - *Thread, - ThreadNameInformationPrivate, - &ThreadNameInfo, - sizeof(ThreadNameInfo)); -#endif - } - return QUIC_STATUS_SUCCESS; -} + ); #define CxPlatThreadDelete(Thread) CxPlatCloseHandle(*(Thread)) #define CxPlatThreadWait(Thread) WaitForSingleObject(*(Thread), INFINITE) typedef uint32_t CXPLAT_THREAD_ID; diff --git a/src/manifest/MsQuicEtw.man b/src/manifest/MsQuicEtw.man index 45054a4439..8c8dc8e2d0 100644 --- a/src/manifest/MsQuicEtw.man +++ b/src/manifest/MsQuicEtw.man @@ -4993,7 +4993,7 @@ /> (new (std::nothrow) uint8_t[DataLength]); @@ -122,6 +126,9 @@ QuicUserMain( if (!SimpleOutput) { printf("App Main returning status %d\n", Status); } + if (!QUIC_SUCCEEDED(Status) && AbortOnFailure) { + CXPLAT_FRE_ASSERTMSG(FALSE, "AbortOnFailure: Non zero exit code detected. Abort to generate core dump."); + } return Status; } diff --git a/src/perf/lib/PerfClient.cpp b/src/perf/lib/PerfClient.cpp index 8a01873a35..ce595f8db2 100644 --- a/src/perf/lib/PerfClient.cpp +++ b/src/perf/lib/PerfClient.cpp @@ -229,7 +229,8 @@ PerfClient::Init( nullptr, PerfClientConnection::TcpConnectCallback, PerfClientConnection::TcpReceiveCallback, - PerfClientConnection::TcpSendCompleteCallback)); + PerfClientConnection::TcpSendCompleteCallback, + TcpDefaultExecutionProfile)); // Client defaults to using LowLatency profile } else { if (UseSendBuffering || !UsePacing) { // Update settings if non-default MsQuicSettings Settings; @@ -293,8 +294,15 @@ PerfClient::Start( // // Configure and start all the workers. // + uint16_t ThreadFlags = + AffinitizeWorkers ? + (uint16_t)CXPLAT_THREAD_FLAG_SET_AFFINITIZE : + (uint16_t)CXPLAT_THREAD_FLAG_SET_IDEAL_PROC; + if (PerfDefaultHighPriority) { + ThreadFlags |= CXPLAT_THREAD_FLAG_HIGH_PRIORITY; + } CXPLAT_THREAD_CONFIG ThreadConfig = { - (uint16_t)(AffinitizeWorkers ? CXPLAT_THREAD_FLAG_SET_AFFINITIZE : CXPLAT_THREAD_FLAG_SET_IDEAL_PROC), + ThreadFlags, 0, "Perf Worker", PerfClientWorker::s_WorkerThread, @@ -336,7 +344,7 @@ PerfClient::Start( return QUIC_STATUS_SUCCESS; } -void +QUIC_STATUS PerfClient::Wait( _In_ int Timeout ) { @@ -359,7 +367,7 @@ PerfClient::Wait( if (GetConnectedConnections() == 0) { WriteOutput("Error: No Successful Connections!\n"); - return; + return QUIC_STATUS_CONNECTION_REFUSED; } unsigned long long CompletedConnections = GetConnectionsCompleted(); @@ -387,6 +395,8 @@ PerfClient::Wait( WriteOutput("No connections or streams completed!\n"); } } + + return QUIC_STATUS_SUCCESS; } uint32_t diff --git a/src/perf/lib/PerfClient.h b/src/perf/lib/PerfClient.h index 5c44b3c439..3522365683 100644 --- a/src/perf/lib/PerfClient.h +++ b/src/perf/lib/PerfClient.h @@ -139,7 +139,7 @@ struct PerfClient { _In_reads_(argc) _Null_terminated_ char* argv[], _In_z_ const char* target); QUIC_STATUS Start(_In_ CXPLAT_EVENT* StopEvent); - void Wait(_In_ int Timeout); + QUIC_STATUS Wait(_In_ int Timeout); uint32_t GetExtraDataLength(); void GetExtraData(_Out_writes_bytes_(Length) uint8_t* Data, _In_ uint32_t Length); diff --git a/src/perf/lib/PerfServer.cpp b/src/perf/lib/PerfServer.cpp index b3c892de80..1ae5f84af2 100644 --- a/src/perf/lib/PerfServer.cpp +++ b/src/perf/lib/PerfServer.cpp @@ -102,7 +102,7 @@ PerfServer::Start( return Listener.Start(PERF_ALPN, &LocalAddr); } -void +QUIC_STATUS PerfServer::Wait( _In_ int Timeout ) { @@ -112,6 +112,7 @@ PerfServer::Wait( CxPlatEventWaitForever(*StopEvent); } Registration.Shutdown(QUIC_CONNECTION_SHUTDOWN_FLAG_NONE, 0); + return QUIC_STATUS_SUCCESS; } void diff --git a/src/perf/lib/PerfServer.h b/src/perf/lib/PerfServer.h index d7b17a50bc..4a10bcfb09 100644 --- a/src/perf/lib/PerfServer.h +++ b/src/perf/lib/PerfServer.h @@ -18,7 +18,7 @@ class PerfServer { public: PerfServer(const QUIC_CREDENTIAL_CONFIG* CredConfig) : - Engine(TcpAcceptCallback, TcpConnectCallback, TcpReceiveCallback, TcpSendCompleteCallback), + Engine(TcpAcceptCallback, TcpConnectCallback, TcpReceiveCallback, TcpSendCompleteCallback, TcpDefaultExecutionProfile), Server(&Engine, CredConfig, this) { CxPlatZeroMemory(&LocalAddr, sizeof(LocalAddr)); QuicAddrSetFamily(&LocalAddr, QUIC_ADDRESS_FAMILY_UNSPEC); @@ -42,7 +42,7 @@ class PerfServer { _In_reads_(argc) _Null_terminated_ char* argv[] ); QUIC_STATUS Start(_In_ CXPLAT_EVENT* StopEvent); - void Wait(int Timeout); + QUIC_STATUS Wait(int Timeout); static CXPLAT_DATAPATH_RECEIVE_CALLBACK DatapathReceive; static void DatapathUnreachable(_In_ CXPLAT_SOCKET*, _In_ void*, _In_ const QUIC_ADDR*) { } diff --git a/src/perf/lib/SecNetPerf.h b/src/perf/lib/SecNetPerf.h index ee7cb28b52..9590503fda 100644 --- a/src/perf/lib/SecNetPerf.h +++ b/src/perf/lib/SecNetPerf.h @@ -42,10 +42,17 @@ #define PERF_MAX_THREAD_COUNT 128 #define PERF_MAX_REQUESTS_PER_SECOND 2000000 // best guess - must increase if we can do better +typedef enum TCP_EXECUTION_PROFILE { + TCP_EXECUTION_PROFILE_LOW_LATENCY, + TCP_EXECUTION_PROFILE_MAX_THROUGHPUT, +} TCP_EXECUTION_PROFILE; + extern QUIC_EXECUTION_PROFILE PerfDefaultExecutionProfile; +extern TCP_EXECUTION_PROFILE TcpDefaultExecutionProfile; extern QUIC_CONGESTION_CONTROL_ALGORITHM PerfDefaultCongestionControl; extern uint8_t PerfDefaultEcnEnabled; extern uint8_t PerfDefaultQeoAllowed; +extern uint8_t PerfDefaultHighPriority; extern CXPLAT_DATAPATH* Datapath; @@ -59,7 +66,7 @@ QuicMainStart( ); extern -void +QUIC_STATUS QuicMainWaitForCompletion( ); diff --git a/src/perf/lib/SecNetPerfMain.cpp b/src/perf/lib/SecNetPerfMain.cpp index 93b2054256..3ba2f5486f 100644 --- a/src/perf/lib/SecNetPerfMain.cpp +++ b/src/perf/lib/SecNetPerfMain.cpp @@ -15,6 +15,7 @@ #include "Tcp.h" const MsQuicApi* MsQuic; +CXPLAT_WORKER_POOL WorkerPool; CXPLAT_DATAPATH* Datapath; CxPlatWatchdog* Watchdog; PerfServer* Server; @@ -22,9 +23,11 @@ PerfClient* Client; uint32_t MaxRuntime = 0; QUIC_EXECUTION_PROFILE PerfDefaultExecutionProfile = QUIC_EXECUTION_PROFILE_LOW_LATENCY; +TCP_EXECUTION_PROFILE TcpDefaultExecutionProfile = TCP_EXECUTION_PROFILE_LOW_LATENCY; QUIC_CONGESTION_CONTROL_ALGORITHM PerfDefaultCongestionControl = QUIC_CONGESTION_CONTROL_ALGORITHM_CUBIC; uint8_t PerfDefaultEcnEnabled = false; uint8_t PerfDefaultQeoAllowed = false; +uint8_t PerfDefaultHighPriority = false; #ifdef _KERNEL_MODE volatile int BufferCurrent; @@ -92,11 +95,12 @@ PrintHelp( " -pollidle: Amount of time to poll while idle before sleeping (default: 0).\n" " -ecn:<0/1> Enables/disables sender-side ECN support. (def:0)\n" " -qeo:<0/1> Allows/disallowes QUIC encryption offload. (def:0)\n" +#ifndef _KERNEL_MODE " -io: Configures a requested network IO model to be used.\n" " - {iocp, rio, xdp, qtip, wsk, epoll, kqueue}\n" -#ifndef _KERNEL_MODE " -cpu: Specify the processor(s) to use.\n" " -cipher: Decimal value of 1 or more QUIC_ALLOWED_CIPHER_SUITE_FLAGS.\n" + " -highpri:<0/1> Configures MsQuic to run threads at high priority. (def:0)\n" #endif // _KERNEL_MODE "\n", PERF_DEFAULT_PORT, @@ -135,7 +139,7 @@ QuicMainStart( uint8_t RawConfig[QUIC_EXECUTION_CONFIG_MIN_SIZE + 256 * sizeof(uint16_t)] = {0}; QUIC_EXECUTION_CONFIG* Config = (QUIC_EXECUTION_CONFIG*)RawConfig; - Config->PollingIdleTimeoutUs = UINT32_MAX; // Default to no sleep. + Config->PollingIdleTimeoutUs = 0; // Default to no polling. bool SetConfig = false; #ifndef _KERNEL_MODE @@ -171,6 +175,12 @@ QuicMainStart( } while (*CpuStr && Config->ProcessorCount < 256); } } + + TryGetValue(argc, argv, "highpri", &PerfDefaultHighPriority); + if (PerfDefaultHighPriority) { + Config->Flags |= QUIC_EXECUTION_CONFIG_FLAG_HIGH_PRIORITY; + SetConfig = true; + } #endif // _KERNEL_MODE if (TryGetValue(argc, argv, "pollidle", &Config->PollingIdleTimeoutUs)) { @@ -193,14 +203,16 @@ QuicMainStart( if (ExecStr != nullptr) { if (IsValue(ExecStr, "lowlat")) { PerfDefaultExecutionProfile = QUIC_EXECUTION_PROFILE_LOW_LATENCY; + TcpDefaultExecutionProfile = TCP_EXECUTION_PROFILE_LOW_LATENCY; } else if (IsValue(ExecStr, "maxtput")) { PerfDefaultExecutionProfile = QUIC_EXECUTION_PROFILE_TYPE_MAX_THROUGHPUT; + TcpDefaultExecutionProfile = TCP_EXECUTION_PROFILE_MAX_THROUGHPUT; } else if (IsValue(ExecStr, "scavenger")) { PerfDefaultExecutionProfile = QUIC_EXECUTION_PROFILE_TYPE_SCAVENGER; } else if (IsValue(ExecStr, "realtime")) { PerfDefaultExecutionProfile = QUIC_EXECUTION_PROFILE_TYPE_REAL_TIME; } else { - WriteOutput("Failed to parse execution profile[%s], use lowlat as default\n", ExecStr); + WriteOutput("Failed to parse execution profile[%s], use lowlat as default for QUIC, lowlat as default for TCP.\n", ExecStr); } } @@ -223,12 +235,15 @@ QuicMainStart( Watchdog = new(std::nothrow) CxPlatWatchdog(WatchdogTimeout, "perf_watchdog", true); } + CxPlatWorkerPoolInit(&WorkerPool); + const CXPLAT_UDP_DATAPATH_CALLBACKS DatapathCallbacks = { PerfServer::DatapathReceive, PerfServer::DatapathUnreachable }; - Status = CxPlatDataPathInitialize(0, &DatapathCallbacks, &TcpEngine::TcpCallbacks, nullptr, &Datapath); + Status = CxPlatDataPathInitialize(0, &DatapathCallbacks, &TcpEngine::TcpCallbacks, &WorkerPool, nullptr, &Datapath); if (QUIC_FAILED(Status)) { + CxPlatWorkerPoolUninit(&WorkerPool); WriteOutput("Datapath for shutdown failed to initialize: %d\n", Status); return Status; } @@ -253,10 +268,10 @@ QuicMainStart( return Status; // QuicMainFree is called on failure } -void +QUIC_STATUS QuicMainWaitForCompletion( ) { - Client ? Client->Wait((int)MaxRuntime) : Server->Wait((int)MaxRuntime); + return Client ? Client->Wait((int)MaxRuntime) : Server->Wait((int)MaxRuntime); } void @@ -272,6 +287,7 @@ QuicMainFree( if (Datapath) { CxPlatDataPathUninitialize(Datapath); + CxPlatWorkerPoolUninit(&WorkerPool); Datapath = nullptr; } diff --git a/src/perf/lib/Tcp.cpp b/src/perf/lib/Tcp.cpp index b92aa76d62..3086a2496f 100644 --- a/src/perf/lib/Tcp.cpp +++ b/src/perf/lib/Tcp.cpp @@ -16,6 +16,7 @@ #endif extern CXPLAT_DATAPATH* Datapath; +extern CXPLAT_WORKER_POOL WorkerPool; // ############################# HELPERS ############################# @@ -105,14 +106,16 @@ TcpEngine::TcpEngine( TcpAcceptHandler AcceptHandler, TcpConnectHandler ConnectHandler, TcpReceiveHandler ReceiveHandler, - TcpSendCompleteHandler SendCompleteHandler) noexcept : + TcpSendCompleteHandler SendCompleteHandler, + TCP_EXECUTION_PROFILE TcpExecutionProfile) noexcept : ProcCount((uint16_t)CxPlatProcCount()), Workers(new(std::nothrow) TcpWorker[ProcCount]), AcceptHandler(AcceptHandler), ConnectHandler(ConnectHandler), - ReceiveHandler(ReceiveHandler), SendCompleteHandler(SendCompleteHandler) + ReceiveHandler(ReceiveHandler), SendCompleteHandler(SendCompleteHandler), + TcpExecutionProfile(TcpExecutionProfile) { CxPlatListInitializeHead(&Connections); for (uint16_t i = 0; i < ProcCount; ++i) { - if (!Workers[i].Initialize(this)) { + if (!Workers[i].Initialize(this, i)) { return; } } @@ -178,23 +181,41 @@ void TcpEngine::RemoveConnection(TcpConnection* Connection) TcpWorker::TcpWorker() { CxPlatEventInitialize(&WakeEvent, FALSE, FALSE); + CxPlatEventInitialize(&DoneEvent, TRUE, FALSE); CxPlatDispatchLockInitialize(&Lock); } TcpWorker::~TcpWorker() { CXPLAT_FRE_ASSERT(!Connections); - if (Initialized) { - CxPlatThreadDelete(&Thread); - } + CXPLAT_FRE_ASSERT(!Initialized); // Shutdown should have been called CxPlatDispatchLockUninitialize(&Lock); + CxPlatEventUninitialize(DoneEvent); CxPlatEventUninitialize(WakeEvent); } -bool TcpWorker::Initialize(TcpEngine* _Engine) +bool TcpWorker::Initialize(TcpEngine* _Engine, uint16_t PartitionIndex) { Engine = _Engine; - CXPLAT_THREAD_CONFIG Config = { 0, 0, "TcpPerfWorker", WorkerThread, this }; + ExecutionContext.Callback = DoWork; + ExecutionContext.Context = this; + ExecutionContext.Ready = TRUE; + ExecutionContext.NextTimeUs = UINT64_MAX; + + #ifndef _KERNEL_MODE // Not supported on kernel mode + if (Engine->TcpExecutionProfile == TCP_EXECUTION_PROFILE_LOW_LATENCY) { + CxPlatAddExecutionContext(&WorkerPool, &ExecutionContext, PartitionIndex); + Initialized = true; + IsExternal = true; + return true; + } + #endif + + uint16_t ThreadFlags = CXPLAT_THREAD_FLAG_SET_IDEAL_PROC; + if (PerfDefaultHighPriority) { + ThreadFlags |= CXPLAT_THREAD_FLAG_HIGH_PRIORITY; + } + CXPLAT_THREAD_CONFIG Config = { ThreadFlags, PartitionIndex, "TcpPerfWorker", WorkerThread, this }; if (QUIC_FAILED( CxPlatThreadCreate( &Config, @@ -209,38 +230,76 @@ bool TcpWorker::Initialize(TcpEngine* _Engine) void TcpWorker::Shutdown() { if (Initialized) { - CxPlatEventSet(WakeEvent); - CxPlatThreadWait(&Thread); + WakeWorkerThread(); + if (IsExternal) { + CxPlatEventWaitForever(DoneEvent); + CxPlatThreadDelete(&Thread); + } else { + CxPlatThreadWait(&Thread); + } + Initialized = false; } } -CXPLAT_THREAD_CALLBACK(TcpWorker::WorkerThread, Context) +void TcpWorker::WakeWorkerThread() { + if (!InterlockedFetchAndSetBoolean(&ExecutionContext.Ready)) { + if (IsExternal) { + CxPlatWakeExecutionContext(&ExecutionContext); + } else { + CxPlatEventSet(WakeEvent); + } + } +} + +// +// Runs one iteration of the worker loop. Returns FALSE when it's time to exit. +// +BOOLEAN +TcpWorker::DoWork( + _Inout_ void* Context, + _Inout_ CXPLAT_EXECUTION_STATE* State + ) { TcpWorker* This = (TcpWorker*)Context; + if (This->Engine->Shutdown) { + CxPlatEventSet(This->DoneEvent); + return FALSE; + } - while (!This->Engine->Shutdown) { - TcpConnection* Connection; - CxPlatDispatchLockAcquire(&This->Lock); - if (!This->Connections) { - Connection = nullptr; - } else { - Connection = This->Connections; - This->Connections = Connection->Next; - if (This->ConnectionsTail == &Connection->Next) { - This->ConnectionsTail = &This->Connections; - } - Connection->QueuedOnWorker = false; - Connection->Next = NULL; - } - CxPlatDispatchLockRelease(&This->Lock); - if (Connection) { - Connection->Process(); - Connection->Release(); - } else { - CxPlatEventWaitForever(This->WakeEvent); + TcpConnection* Connection = nullptr; + CxPlatDispatchLockAcquire(&This->Lock); + if (This->Connections) { + Connection = This->Connections; + This->Connections = Connection->Next; + if (This->ConnectionsTail == &Connection->Next) { + This->ConnectionsTail = &This->Connections; } + Connection->QueuedOnWorker = false; + Connection->Next = NULL; + } + CxPlatDispatchLockRelease(&This->Lock); + + if (Connection) { + Connection->Process(); + Connection->Release(); + This->ExecutionContext.Ready = TRUE; // We just did work, let's keep this thread hot. + State->NoWorkCount = 0; } + return TRUE; +} + +CXPLAT_THREAD_CALLBACK(TcpWorker::WorkerThread, Context) +{ + TcpWorker* This = (TcpWorker*)Context; + CXPLAT_EXECUTION_STATE DummyState = { + 0, 0, 0, UINT32_MAX, 0, CxPlatCurThreadID() + }; + while (DoWork(This, &DummyState)) { + if (!InterlockedFetchAndClearBoolean(&This->ExecutionContext.Ready)) { + CxPlatEventWaitForever(This->WakeEvent); // Wait for more work + } + } CXPLAT_THREAD_RETURN(0); } @@ -257,7 +316,7 @@ bool TcpWorker::QueueConnection(TcpConnection* Connection) Connection->QueuedOnWorker = true; *ConnectionsTail = Connection; ConnectionsTail = &Connection->Next; - CxPlatEventSet(WakeEvent); + WakeWorkerThread(); } else { Result = false; } @@ -307,7 +366,7 @@ bool TcpServer::Start(const QUIC_ADDR* LocalAddress) _IRQL_requires_max_(DISPATCH_LEVEL) _Function_class_(CXPLAT_DATAPATH_ACCEPT_CALLBACK) -void +QUIC_STATUS TcpServer::AcceptCallback( _In_ CXPLAT_SOCKET* /* ListenerSocket */, _In_ void* ListenerContext, @@ -318,6 +377,7 @@ TcpServer::AcceptCallback( auto This = (TcpServer*)ListenerContext; auto Connection = new(std::nothrow) TcpConnection(This->Engine, This->SecConfig, AcceptSocket, This); *AcceptClientContext = Connection; + return QUIC_STATUS_SUCCESS; } // ############################ CONNECTION ############################ @@ -465,10 +525,11 @@ TcpConnection::ConnectCallback( Connected); if (Connected) { This->StartTls = true; - } else { + This->Queue(); + } else if (!This->Shutdown) { This->Shutdown = true; + This->Queue(); } - This->Queue(); } _IRQL_requires_max_(DISPATCH_LEVEL) @@ -512,22 +573,30 @@ void TcpConnection::SendCompleteCallback( _In_ CXPLAT_SOCKET* /* Socket */, _In_ void* Context, - _In_ QUIC_STATUS /* Status */, + _In_ QUIC_STATUS Status, _In_ uint32_t ByteCount ) { TcpConnection* This = (TcpConnection*)Context; + bool QueueWork = false; QuicTraceLogVerbose( PerfTcpSendCompleteCallback, - "[perf][tcp][%p] SendComplete callback", - This); + "[perf][tcp][%p] SendComplete callback, %u", + This, + (uint32_t)Status); CxPlatDispatchLockAcquire(&This->Lock); - if (This->TotalSendCompleteOffset != UINT64_MAX) { + if (QUIC_FAILED(Status)) { + if (!This->Shutdown) { + This->Shutdown = true; + QueueWork = true; + } + } else if (This->TotalSendCompleteOffset != UINT64_MAX) { This->TotalSendCompleteOffset += ByteCount; This->IndicateSendComplete = true; + QueueWork = true; } CxPlatDispatchLockRelease(&This->Lock); - if (This->TotalSendCompleteOffset != UINT64_MAX) { + if (QueueWork) { This->Queue(); } } @@ -602,10 +671,7 @@ void TcpConnection::Process() } } if (BatchedSendData && !Shutdown) { - if (QUIC_FAILED( - CxPlatSocketSend(Socket, &Route, BatchedSendData))) { - Shutdown = true; - } + CxPlatSocketSend(Socket, &Route, BatchedSendData); BatchedSendData = nullptr; } if (IndicateSendComplete) { @@ -700,7 +766,7 @@ bool TcpConnection::ProcessTls(const uint8_t* Buffer, uint32_t BufferLength) IndicateConnect = true; } - while (BaseOffset < TlsState.BufferTotalLength) { + while (!Shutdown && BaseOffset < TlsState.BufferTotalLength) { if (TlsState.BufferOffsetHandshake) { if (BaseOffset < TlsState.BufferOffsetHandshake) { uint16_t Length = (uint16_t)(TlsState.BufferOffsetHandshake - BaseOffset); @@ -754,7 +820,9 @@ bool TcpConnection::SendTlsData(const uint8_t* Buffer, uint16_t BufferLength, ui } SendBuffer->Length = sizeof(TcpFrame) + Frame->Length + CXPLAT_ENCRYPTION_OVERHEAD; - return FinalizeSendBuffer(SendBuffer); + FinalizeSendBuffer(SendBuffer); + + return true; } bool TcpConnection::ProcessReceive() @@ -954,11 +1022,9 @@ bool TcpConnection::ProcessSend() } SendBuffer->Length = sizeof(TcpFrame) + Frame->Length + CXPLAT_ENCRYPTION_OVERHEAD; - if (!FinalizeSendBuffer(SendBuffer)) { - return false; - } + FinalizeSendBuffer(SendBuffer); - } while (NextSendData->Length > Offset); + } while (!Shutdown && NextSendData->Length > Offset); NextSendData->Offset = TotalSendOffset; NextSendData = NextSendData->Next; @@ -1034,18 +1100,14 @@ void TcpConnection::FreeSendBuffer(QUIC_BUFFER* SendBuffer) CxPlatSendDataFreeBuffer(BatchedSendData, SendBuffer); } -bool TcpConnection::FinalizeSendBuffer(QUIC_BUFFER* SendBuffer) +void TcpConnection::FinalizeSendBuffer(QUIC_BUFFER* SendBuffer) { TotalSendOffset += SendBuffer->Length; if (SendBuffer->Length != TLS_BLOCK_SIZE || CxPlatSendDataIsFull(BatchedSendData)) { - auto Status = CxPlatSocketSend(Socket, &Route, BatchedSendData); + CxPlatSocketSend(Socket, &Route, BatchedSendData); BatchedSendData = nullptr; - if (QUIC_FAILED(Status)) { - return false; - } } - return true; } bool TcpConnection::Send(TcpSendData* Data) diff --git a/src/perf/lib/Tcp.h b/src/perf/lib/Tcp.h index 431aa65393..5840cef8f0 100644 --- a/src/perf/lib/Tcp.h +++ b/src/perf/lib/Tcp.h @@ -95,12 +95,14 @@ class TcpEngine { const TcpConnectHandler ConnectHandler; const TcpReceiveHandler ReceiveHandler; const TcpSendCompleteHandler SendCompleteHandler; + const TCP_EXECUTION_PROFILE TcpExecutionProfile; public: TcpEngine( TcpAcceptHandler AcceptHandler, TcpConnectHandler ConnectHandler, TcpReceiveHandler ReceiveHandler, - TcpSendCompleteHandler SendCompleteHandler) noexcept; + TcpSendCompleteHandler SendCompleteHandler, + TCP_EXECUTION_PROFILE TcpExecutionProfile) noexcept; ~TcpEngine() noexcept; bool IsInitialized() const { return Initialized; } bool AddConnection(TcpConnection* Connection, uint16_t PartitionIndex); @@ -110,19 +112,27 @@ class TcpEngine { class TcpWorker { friend class TcpEngine; friend class TcpConnection; + CXPLAT_EXECUTION_CONTEXT ExecutionContext; bool Initialized{false}; + bool IsExternal{false}; TcpEngine* Engine{nullptr}; CXPLAT_THREAD Thread; CXPLAT_EVENT WakeEvent; + CXPLAT_EVENT DoneEvent; CXPLAT_DISPATCH_LOCK Lock; TcpConnection* Connections{nullptr}; TcpConnection** ConnectionsTail{&Connections}; TcpWorker(); ~TcpWorker(); - bool Initialize(TcpEngine* _Engine); + bool Initialize(TcpEngine* _Engine, uint16_t PartitionIndex); void Shutdown(); + void WakeWorkerThread(); static CXPLAT_THREAD_CALLBACK(WorkerThread, Context); bool QueueConnection(TcpConnection* Connection); + static BOOLEAN DoWork( + _Inout_ void* Context, + _Inout_ CXPLAT_EXECUTION_STATE* State + ); }; class TcpServer { @@ -145,7 +155,7 @@ class TcpServer { static _IRQL_requires_max_(DISPATCH_LEVEL) _Function_class_(CXPLAT_DATAPATH_ACCEPT_CALLBACK) - void + QUIC_STATUS AcceptCallback( _In_ CXPLAT_SOCKET* ListenerSocket, _In_ void* ListenerContext, @@ -258,7 +268,7 @@ class TcpConnection { bool EncryptFrame(TcpFrame* Frame); QUIC_BUFFER* NewSendBuffer(); void FreeSendBuffer(QUIC_BUFFER* SendBuffer); - bool FinalizeSendBuffer(QUIC_BUFFER* SendBuffer); + void FinalizeSendBuffer(QUIC_BUFFER* SendBuffer); bool TryAddRef() { return CxPlatRefIncrementNonZero(&Ref, 1) != FALSE; } void Release() { if (CxPlatRefDecrement(&Ref)) delete this; } public: diff --git a/src/platform/CMakeLists.txt b/src/platform/CMakeLists.txt index d79d16841d..eca936787c 100644 --- a/src/platform/CMakeLists.txt +++ b/src/platform/CMakeLists.txt @@ -34,6 +34,12 @@ else() else() set(SOURCES ${SOURCES} datapath_kqueue.c) endif() + + # Compile for Android failed by __atomic_add_fetch(), only emulator and some old ChromeBooks are X86, so the performance penalty may be acceptable, do not patch all the atomic usage for now + # > error: misaligned atomic operation may incur significant performance penalty; the expected alignment (8 bytes) exceeds the actual alignment (4 bytes) + if (ANDROID AND ANDROID_ABI STREQUAL "x86") + add_compile_options(-Wno-atomic-alignment) + endif() endif() if (QUIC_TLS STREQUAL "schannel") diff --git a/src/platform/datapath_epoll.c b/src/platform/datapath_epoll.c index f6cd826e7e..18f749749e 100644 --- a/src/platform/datapath_epoll.c +++ b/src/platform/datapath_epoll.c @@ -354,7 +354,7 @@ CxPlatProcessorContextInitialize( CXPLAT_DBG_ASSERT(Datapath != NULL); DatapathPartition->Datapath = Datapath; DatapathPartition->PartitionIndex = PartitionIndex; - DatapathPartition->EventQ = CxPlatWorkerGetEventQ(PartitionIndex); + DatapathPartition->EventQ = CxPlatWorkerPoolGetEventQ(Datapath->WorkerPool, PartitionIndex); CxPlatRefInitialize(&DatapathPartition->RefCount); CxPlatPoolInitialize(TRUE, Datapath->RecvBlockSize, QUIC_POOL_DATA, &DatapathPartition->RecvBlockPool); CxPlatPoolInitialize(TRUE, Datapath->SendDataSize, QUIC_POOL_DATA, &DatapathPartition->SendBlockPool); @@ -365,6 +365,7 @@ DataPathInitialize( _In_ uint32_t ClientRecvDataLength, _In_opt_ const CXPLAT_UDP_DATAPATH_CALLBACKS* UdpCallbacks, _In_opt_ const CXPLAT_TCP_DATAPATH_CALLBACKS* TcpCallbacks, + _In_ CXPLAT_WORKER_POOL* WorkerPool, _In_opt_ QUIC_EXECUTION_CONFIG* Config, _Out_ CXPLAT_DATAPATH** NewDatapath ) @@ -386,8 +387,11 @@ DataPathInitialize( return QUIC_STATUS_INVALID_PARAMETER; } } + if (WorkerPool == NULL) { + return QUIC_STATUS_INVALID_PARAMETER; + } - if (!CxPlatWorkersLazyStart(Config)) { + if (!CxPlatWorkerPoolLazyStart(WorkerPool, Config)) { return QUIC_STATUS_OUT_OF_MEMORY; } @@ -415,6 +419,7 @@ DataPathInitialize( if (TcpCallbacks) { Datapath->TcpHandlers = *TcpCallbacks; } + Datapath->WorkerPool = WorkerPool; Datapath->PartitionCount = PartitionCount; Datapath->Features = CXPLAT_DATAPATH_FEATURE_LOCAL_PORT_SHARING; @@ -429,7 +434,7 @@ DataPathInitialize( Datapath, i, &Datapath->Partitions[i]); } - CXPLAT_FRE_ASSERT(CxPlatRundownAcquire(&CxPlatWorkerRundown)); + CXPLAT_FRE_ASSERT(CxPlatRundownAcquire(&WorkerPool->Rundown)); *NewDatapath = Datapath; return QUIC_STATUS_SUCCESS; @@ -447,8 +452,8 @@ CxPlatDataPathRelease( CXPLAT_DBG_ASSERT(Datapath->Uninitialized); Datapath->Freed = TRUE; #endif + CxPlatRundownRelease(&Datapath->WorkerPool->Rundown); CXPLAT_FREE(Datapath, QUIC_POOL_DATAPATH); - CxPlatRundownRelease(&CxPlatWorkerRundown); } } @@ -896,7 +901,8 @@ CxPlatSocketContextInitialize( // Only set SO_REUSEPORT on a server socket, otherwise the client could be // assigned a server port (unless it's forcing sharing). // - if (Config->Flags & CXPLAT_SOCKET_FLAG_SHARE || Config->RemoteAddress == NULL) { + if ((Config->Flags & CXPLAT_SOCKET_FLAG_SHARE || Config->RemoteAddress == NULL) && + SocketContext->Binding->Datapath->PartitionCount > 1) { // // The port is shared across processors. // @@ -1532,7 +1538,12 @@ CxPlatSocketContextAcceptCompletion( goto Error; } - SocketContext->AcceptSocket->SocketContexts[0].SocketFd = accept(SocketContext->SocketFd, NULL, NULL); + socklen_t AssignedRemoteAddressLength = sizeof(SocketContext->AcceptSocket->RemoteAddress); + SocketContext->AcceptSocket->SocketContexts[0].SocketFd = + accept( + SocketContext->SocketFd, + (struct sockaddr*)&SocketContext->AcceptSocket->RemoteAddress, + &AssignedRemoteAddressLength); if (SocketContext->AcceptSocket->SocketContexts[0].SocketFd == INVALID_SOCKET) { Status = errno; QuicTraceEvent( @@ -1544,13 +1555,39 @@ CxPlatSocketContextAcceptCompletion( goto Error; } + socklen_t AssignedLocalAddressLength = sizeof(SocketContext->AcceptSocket->LocalAddress); + int Result = + getsockname( + SocketContext->AcceptSocket->SocketContexts[0].SocketFd, + (struct sockaddr*)&SocketContext->AcceptSocket->LocalAddress, + &AssignedLocalAddressLength); + if (Result == SOCKET_ERROR) { + QuicTraceEvent( + DatapathErrorStatus, + "[data][%p] ERROR, %u, %s.", + SocketContext->Binding, + Status, + "getsockname failed"); + goto Error; + } + + CxPlatConvertFromMappedV6( + &SocketContext->AcceptSocket->LocalAddress, + &SocketContext->AcceptSocket->LocalAddress); + CxPlatConvertFromMappedV6( + &SocketContext->AcceptSocket->RemoteAddress, + &SocketContext->AcceptSocket->RemoteAddress); + CxPlatSocketContextSetEvents(&SocketContext->AcceptSocket->SocketContexts[0], EPOLL_CTL_ADD, EPOLLIN); SocketContext->AcceptSocket->SocketContexts[0].IoStarted = TRUE; - Datapath->TcpHandlers.Accept( + Status = Datapath->TcpHandlers.Accept( SocketContext->Binding, SocketContext->Binding->ClientContext, SocketContext->AcceptSocket, &SocketContext->AcceptSocket->ClientContext); + if (QUIC_FAILED(Status)) { + goto Error; + } SocketContext->AcceptSocket = NULL; @@ -2222,7 +2259,7 @@ CxPlatSendDataSend( _In_ CXPLAT_SEND_DATA* SendData ); -QUIC_STATUS +void SocketSend( _In_ CXPLAT_SOCKET* Socket, _In_ const CXPLAT_ROUTE* Route, @@ -2272,7 +2309,7 @@ SocketSend( &SocketContext->FlushTxSqe.Sqe, &SocketContext->FlushTxSqe)); } - return QUIC_STATUS_SUCCESS; + return; } // @@ -2288,19 +2325,16 @@ SocketSend( CxPlatListInsertTail(&SocketContext->TxQueue, &SendData->TxEntry); CxPlatLockRelease(&SocketContext->TxQueueLock); CxPlatSocketContextSetEvents(SocketContext, EPOLL_CTL_MOD, EPOLLIN | EPOLLOUT); - Status = QUIC_STATUS_SUCCESS; } else { if (Socket->Type != CXPLAT_SOCKET_UDP) { SocketContext->Binding->Datapath->TcpHandlers.SendComplete( SocketContext->Binding, SocketContext->Binding->ClientContext, - errno, + Status, SendData->TotalSize); } CxPlatSendDataFree(SendData); } - - return Status; } // @@ -2337,7 +2371,7 @@ CxPlatSendDataPopulateAncillaryData( CMsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); struct in_pktinfo *PktInfo = (struct in_pktinfo*)CMSG_DATA(CMsg); PktInfo->ipi_ifindex = SendData->LocalAddress.Ipv6.sin6_scope_id; - PktInfo->ipi_spec_dst.s_addr = 0; + PktInfo->ipi_spec_dst = SendData->LocalAddress.Ipv4.sin_addr; PktInfo->ipi_addr = SendData->LocalAddress.Ipv4.sin_addr; } else { Mhdr->msg_controllen += CMSG_SPACE(sizeof(struct in6_pktinfo)); @@ -2593,7 +2627,8 @@ CxPlatSocketContextFlushTxQueue( CxPlatLockRelease(&SocketContext->TxQueueLock); while (SendData != NULL) { - if (CxPlatSendDataSend(SendData) == QUIC_STATUS_PENDING) { + QUIC_STATUS Status = CxPlatSendDataSend(SendData); + if (Status == QUIC_STATUS_PENDING) { if (!SendAlreadyPending) { // // Add the EPOLLOUT event since we have more pending sends. @@ -2609,7 +2644,7 @@ CxPlatSocketContextFlushTxQueue( SocketContext->Binding->Datapath->TcpHandlers.SendComplete( SocketContext->Binding, SocketContext->Binding->ClientContext, - errno, + Status, SendData->TotalSize); } CxPlatSendDataFree(SendData); diff --git a/src/platform/datapath_kqueue.c b/src/platform/datapath_kqueue.c index ae6e62bd6d..12aabccb68 100644 --- a/src/platform/datapath_kqueue.c +++ b/src/platform/datapath_kqueue.c @@ -358,6 +358,11 @@ typedef struct CXPLAT_DATAPATH { // CXPLAT_UDP_DATAPATH_CALLBACKS UdpHandlers; + // + // The Worker pool + // + CXPLAT_WORKER_POOL* WorkerPool; + // // Synchronization mechanism for cleanup. // @@ -408,7 +413,7 @@ CxPlatProcessorContextInitialize( CXPLAT_DBG_ASSERT(Datapath != NULL); DatapathPartition->Datapath = Datapath; DatapathPartition->PartitionIndex = PartitionIndex; - DatapathPartition->EventQ = CxPlatWorkerGetEventQ(PartitionIndex); + DatapathPartition->EventQ = CxPlatWorkerPoolGetEventQ(Datapath->WorkerPool, PartitionIndex); CxPlatRefInitialize(&DatapathPartition->RefCount); CxPlatPoolInitialize( @@ -438,6 +443,7 @@ CxPlatDataPathInitialize( _In_ uint32_t ClientRecvDataLength, _In_opt_ const CXPLAT_UDP_DATAPATH_CALLBACKS* UdpCallbacks, _In_opt_ const CXPLAT_TCP_DATAPATH_CALLBACKS* TcpCallbacks, + _In_ CXPLAT_WORKER_POOL* WorkerPool, _In_opt_ QUIC_EXECUTION_CONFIG* Config, _Out_ CXPLAT_DATAPATH** NewDataPath ) @@ -451,8 +457,11 @@ CxPlatDataPathInitialize( return QUIC_STATUS_INVALID_PARAMETER; } } + if (WorkerPool == NULL) { + return QUIC_STATUS_INVALID_PARAMETER; + } - if (!CxPlatWorkersLazyStart(Config)) { + if (!CxPlatWorkerPoolLazyStart(WorkerPool, Config)) { return QUIC_STATUS_OUT_OF_MEMORY; } @@ -480,6 +489,7 @@ CxPlatDataPathInitialize( if (UdpCallbacks) { Datapath->UdpHandlers = *UdpCallbacks; } + Datapath->WorkerPool = WorkerPool; Datapath->PartitionCount = 1; //PartitionCount; // Darwin only supports a single receiver CxPlatRefInitializeEx(&Datapath->RefCount, Datapath->PartitionCount); @@ -491,7 +501,7 @@ CxPlatDataPathInitialize( &Datapath->Partitions[i]); } - CXPLAT_FRE_ASSERT(CxPlatRundownAcquire(&CxPlatWorkerRundown)); + CXPLAT_FRE_ASSERT(CxPlatRundownAcquire(&WorkerPool->Rundown)); *NewDataPath = Datapath; return QUIC_STATUS_SUCCESS; @@ -509,8 +519,8 @@ CxPlatDataPathRelease( CXPLAT_DBG_ASSERT(Datapath->Uninitialized); Datapath->Freed = TRUE; #endif + CxPlatRundownRelease(&Datapath->WorkerPool->Rundown); CXPLAT_FREE(Datapath, QUIC_POOL_DATAPATH); - CxPlatRundownRelease(&CxPlatWorkerRundown); } } @@ -1580,6 +1590,16 @@ CxPlatSocketGetRemoteAddress( *Address = Socket->RemoteAddress; } +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +CxPlatSocketRawSocketAvailable( + _In_ CXPLAT_SOCKET* Socket + ) +{ + UNREFERENCED_PARAMETER(Socket); + return FALSE; +} + void CxPlatRecvDataReturn( _In_opt_ CXPLAT_RECV_DATA* RecvDataChain @@ -1992,6 +2012,7 @@ CxPlatSocketSendInternal( PktInfo = (struct in_pktinfo*) CMSG_DATA(CMsg); // TODO: Use Ipv4 instead of Ipv6. PktInfo->ipi_ifindex = LocalAddress->Ipv6.sin6_scope_id; + PktInfo->ipi_spec_dst = LocalAddress->Ipv4.sin_addr; PktInfo->ipi_addr = LocalAddress->Ipv4.sin_addr; } else { CMsg->cmsg_level = IPPROTO_IPV6; @@ -2079,7 +2100,7 @@ CxPlatSocketSendInternal( return Status; } -QUIC_STATUS +void CxPlatSocketSend( _In_ CXPLAT_SOCKET* Socket, _In_ const CXPLAT_ROUTE* Route, @@ -2088,18 +2109,12 @@ CxPlatSocketSend( { UNREFERENCED_PARAMETER(Socket); CXPLAT_DBG_ASSERT(Route->Queue); - CXPLAT_SOCKET_CONTEXT* SocketContext = Route->Queue; - QUIC_STATUS Status = - CxPlatSocketSendInternal( - SocketContext, - &Route->LocalAddress, - &Route->RemoteAddress, - SendData, - FALSE); - if (Status == QUIC_STATUS_PENDING) { - Status = QUIC_STATUS_SUCCESS; - } - return Status; + CxPlatSocketSendInternal( + Route->Queue, + &Route->LocalAddress, + &Route->RemoteAddress, + SendData, + FALSE); } uint16_t diff --git a/src/platform/datapath_raw.c b/src/platform/datapath_raw.c index e3967f647b..f9b827eafd 100644 --- a/src/platform/datapath_raw.c +++ b/src/platform/datapath_raw.c @@ -24,6 +24,7 @@ RawDataPathInitialize( _In_ uint32_t ClientRecvContextLength, _In_opt_ QUIC_EXECUTION_CONFIG* Config, _In_opt_ const CXPLAT_DATAPATH* ParentDataPath, + _In_ CXPLAT_WORKER_POOL* WorkerPool, _Out_ CXPLAT_DATAPATH_RAW** NewDataPath ) { @@ -32,6 +33,10 @@ RawDataPathInitialize( BOOLEAN DpRawInitialized = FALSE; BOOLEAN SockPoolInitialized = FALSE; + if (WorkerPool == NULL) { + return QUIC_STATUS_INVALID_PARAMETER; + } + if (NewDataPath == NULL) { return QUIC_STATUS_INVALID_PARAMETER; } @@ -46,7 +51,9 @@ RawDataPathInitialize( return QUIC_STATUS_OUT_OF_MEMORY; } CxPlatZeroMemory(DataPath, DatapathSize); - CXPLAT_FRE_ASSERT(CxPlatRundownAcquire(&CxPlatWorkerRundown)); + CXPLAT_FRE_ASSERT(CxPlatRundownAcquire(&WorkerPool->Rundown)); + + DataPath->WorkerPool = WorkerPool; if (Config && (Config->Flags & QUIC_EXECUTION_CONFIG_FLAG_QTIP)) { DataPath->UseTcp = TRUE; @@ -58,7 +65,7 @@ RawDataPathInitialize( } SockPoolInitialized = TRUE; - Status = CxPlatDpRawInitialize(DataPath, ClientRecvContextLength, Config); + Status = CxPlatDpRawInitialize(DataPath, ClientRecvContextLength, WorkerPool, Config); if (QUIC_FAILED(Status)) { goto Error; } @@ -86,7 +93,7 @@ RawDataPathInitialize( CxPlatSockPoolUninitialize(&DataPath->SocketPool); } CXPLAT_FREE(DataPath, QUIC_POOL_DATAPATH); - CxPlatRundownRelease(&CxPlatWorkerRundown); + CxPlatRundownRelease(&WorkerPool->Rundown); } } @@ -122,8 +129,8 @@ CxPlatDataPathUninitializeComplete( Datapath->Freed = TRUE; #endif CxPlatSockPoolUninitialize(&Datapath->SocketPool); + CxPlatRundownRelease(&Datapath->WorkerPool->Rundown); CXPLAT_FREE(Datapath, QUIC_POOL_DATAPATH); - CxPlatRundownRelease(&CxPlatWorkerRundown); } _IRQL_requires_max_(PASSIVE_LEVEL) diff --git a/src/platform/datapath_raw.h b/src/platform/datapath_raw.h index 44d8fa5656..c23d63d449 100644 --- a/src/platform/datapath_raw.h +++ b/src/platform/datapath_raw.h @@ -47,6 +47,11 @@ typedef struct QUIC_CACHEALIGN CXPLAT_ROUTE_RESOLUTION_WORKER { typedef struct CXPLAT_DATAPATH_RAW { const CXPLAT_DATAPATH *ParentDataPath; + // + // The Worker pool + // + CXPLAT_WORKER_POOL* WorkerPool; + CXPLAT_SOCKET_POOL SocketPool; CXPLAT_ROUTE_RESOLUTION_WORKER* RouteResolutionWorker; @@ -107,6 +112,7 @@ QUIC_STATUS CxPlatDpRawInitialize( _Inout_ CXPLAT_DATAPATH_RAW* Datapath, _In_ uint32_t ClientRecvContextLength, + _In_ CXPLAT_WORKER_POOL* WorkerPool, _In_opt_ const QUIC_EXECUTION_CONFIG* Config ); diff --git a/src/platform/datapath_raw_dpdk.c b/src/platform/datapath_raw_dpdk.c index dec8180f9c..b151a5d0ce 100644 --- a/src/platform/datapath_raw_dpdk.c +++ b/src/platform/datapath_raw_dpdk.c @@ -138,9 +138,11 @@ QUIC_STATUS CxPlatDpRawInitialize( _Inout_ CXPLAT_DATAPATH* Datapath, _In_ uint32_t ClientRecvContextLength, + _In_ CXPLAT_WORKER_POOL* WorkerPool, _In_opt_ const QUIC_EXECUTION_CONFIG* Config ) { + UNREFERENCED_PARAMETER(WorkerPool); DPDK_DATAPATH* Dpdk = (DPDK_DATAPATH*)Datapath; CXPLAT_THREAD_CONFIG Config = { 0, 0, "DpdkMain", CxPlatDpdkMainThread, Dpdk diff --git a/src/platform/datapath_raw_dummy.c b/src/platform/datapath_raw_dummy.c index 05c9353ede..146feb637a 100644 --- a/src/platform/datapath_raw_dummy.c +++ b/src/platform/datapath_raw_dummy.c @@ -56,12 +56,14 @@ RawDataPathInitialize( _In_ uint32_t ClientRecvContextLength, _In_opt_ QUIC_EXECUTION_CONFIG* Config, _In_opt_ const CXPLAT_DATAPATH* ParentDataPath, + _In_ CXPLAT_WORKER_POOL* WorkerPool, _Out_ CXPLAT_DATAPATH_RAW** DataPath ) { UNREFERENCED_PARAMETER(ClientRecvContextLength); UNREFERENCED_PARAMETER(Config); UNREFERENCED_PARAMETER(ParentDataPath); + UNREFERENCED_PARAMETER(WorkerPool); UNREFERENCED_PARAMETER(DataPath); return QUIC_STATUS_NOT_SUPPORTED; } diff --git a/src/platform/datapath_raw_xdp_linux.c b/src/platform/datapath_raw_xdp_linux.c index eaef116164..d68bb66f50 100644 --- a/src/platform/datapath_raw_xdp_linux.c +++ b/src/platform/datapath_raw_xdp_linux.c @@ -672,12 +672,17 @@ QUIC_STATUS CxPlatDpRawInitialize( _Inout_ CXPLAT_DATAPATH_RAW* Datapath, _In_ uint32_t ClientRecvContextLength, + _In_ CXPLAT_WORKER_POOL* WorkerPool, _In_opt_ const QUIC_EXECUTION_CONFIG* Config ) { XDP_DATAPATH* Xdp = (XDP_DATAPATH*)Datapath; QUIC_STATUS Status = QUIC_STATUS_SUCCESS; + if (WorkerPool == NULL) { + return QUIC_STATUS_INVALID_PARAMETER; + } + CxPlatXdpReadConfig(Xdp); CxPlatListInitializeHead(&Xdp->Interfaces); Xdp->PollingIdleTimeoutUs = Config ? Config->PollingIdleTimeoutUs : 0; @@ -791,7 +796,7 @@ CxPlatDpRawInitialize( Partition->ShutdownSqe.CqeType = CXPLAT_CQE_TYPE_XDP_SHUTDOWN; CxPlatRefIncrement(&Xdp->RefCount); CxPlatRundownAcquire(&Xdp->Rundown); - Partition->EventQ = CxPlatWorkerGetEventQ((uint16_t)i); + Partition->EventQ = CxPlatWorkerPoolGetEventQ(WorkerPool, (uint16_t)i); if (!CxPlatSqeInitialize( Partition->EventQ, @@ -833,7 +838,7 @@ CxPlatDpRawInitialize( Partition, QueueCount); - CxPlatAddExecutionContext(&Partition->Ec, Partition->PartitionIndex); + CxPlatAddExecutionContext(WorkerPool, &Partition->Ec, Partition->PartitionIndex); } Error: diff --git a/src/platform/datapath_raw_xdp_win.c b/src/platform/datapath_raw_xdp_win.c index 473569ec86..2537cdd243 100644 --- a/src/platform/datapath_raw_xdp_win.c +++ b/src/platform/datapath_raw_xdp_win.c @@ -980,12 +980,17 @@ QUIC_STATUS CxPlatDpRawInitialize( _Inout_ CXPLAT_DATAPATH_RAW* Datapath, _In_ uint32_t ClientRecvContextLength, + _In_ CXPLAT_WORKER_POOL* WorkerPool, _In_opt_ const QUIC_EXECUTION_CONFIG* Config ) { XDP_DATAPATH* Xdp = (XDP_DATAPATH*)Datapath; QUIC_STATUS Status; + if (WorkerPool == NULL) { + return QUIC_STATUS_INVALID_PARAMETER; + } + CxPlatListInitializeHead(&Xdp->Interfaces); if (QUIC_FAILED(XdpLoadApi(XDP_API_VERSION_1, &Xdp->XdpApiLoadContext, &Xdp->XdpApi))) { Status = QUIC_STATUS_NOT_SUPPORTED; @@ -1152,7 +1157,7 @@ CxPlatDpRawInitialize( Partition->Ec.Context = &Xdp->Partitions[i]; Partition->ShutdownSqe.CqeType = CXPLAT_CQE_TYPE_SOCKET_SHUTDOWN; CxPlatRefIncrement(&Xdp->RefCount); - Partition->EventQ = CxPlatWorkerGetEventQ((uint16_t)i); + Partition->EventQ = CxPlatWorkerPoolGetEventQ(WorkerPool, (uint16_t)i); uint32_t QueueCount = 0; XDP_QUEUE* Queue = Partition->Queues; @@ -1187,7 +1192,7 @@ CxPlatDpRawInitialize( QueueCount); UNREFERENCED_PARAMETER(QueueCount); - CxPlatAddExecutionContext(&Partition->Ec, Partition->PartitionIndex); + CxPlatAddExecutionContext(WorkerPool, &Partition->Ec, Partition->PartitionIndex); } Status = QUIC_STATUS_SUCCESS; diff --git a/src/platform/datapath_winkernel.c b/src/platform/datapath_winkernel.c index aea89cf1b5..111b72890e 100644 --- a/src/platform/datapath_winkernel.c +++ b/src/platform/datapath_winkernel.c @@ -793,10 +793,12 @@ CxPlatDataPathInitialize( _In_ uint32_t ClientRecvDataLength, _In_opt_ const CXPLAT_UDP_DATAPATH_CALLBACKS* UdpCallbacks, _In_opt_ const CXPLAT_TCP_DATAPATH_CALLBACKS* TcpCallbacks, + _In_ CXPLAT_WORKER_POOL* WorkerPool, _In_opt_ QUIC_EXECUTION_CONFIG* Config, _Out_ CXPLAT_DATAPATH* *NewDataPath ) { + UNREFERENCED_PARAMETER(WorkerPool); QUIC_STATUS Status; WSK_CLIENT_NPI WskClientNpi = { NULL, &WskAppDispatch }; uint32_t DatapathLength; @@ -2075,6 +2077,16 @@ CxPlatSocketGetRemoteAddress( *Address = Binding->RemoteAddress; } +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +CxPlatSocketRawSocketAvailable( + _In_ CXPLAT_SOCKET* Socket + ) +{ + UNREFERENCED_PARAMETER(Socket); + return FALSE; +} + _IRQL_requires_max_(DISPATCH_LEVEL) DATAPATH_RX_IO_BLOCK* CxPlatSocketAllocRxIoBlock( @@ -2992,7 +3004,7 @@ CxPlatSocketPrepareSendData( } _IRQL_requires_max_(DISPATCH_LEVEL) -QUIC_STATUS +void CxPlatSocketSend( _In_ CXPLAT_SOCKET* Binding, _In_ const CXPLAT_ROUTE* Route, @@ -3110,8 +3122,6 @@ CxPlatSocketSend( // Callback still gets invoked on failure to do the cleanup. // } - - return STATUS_SUCCESS; } _IRQL_requires_max_(DISPATCH_LEVEL) diff --git a/src/platform/datapath_winuser.c b/src/platform/datapath_winuser.c index dbcdc66f91..bfaafb947d 100644 --- a/src/platform/datapath_winuser.c +++ b/src/platform/datapath_winuser.c @@ -758,6 +758,7 @@ DataPathInitialize( _In_ uint32_t ClientRecvDataLength, _In_opt_ const CXPLAT_UDP_DATAPATH_CALLBACKS* UdpCallbacks, _In_opt_ const CXPLAT_TCP_DATAPATH_CALLBACKS* TcpCallbacks, + _In_ CXPLAT_WORKER_POOL* WorkerPool, _In_opt_ QUIC_EXECUTION_CONFIG* Config, _Out_ CXPLAT_DATAPATH** NewDatapath ) @@ -789,8 +790,11 @@ DataPathInitialize( goto Exit; } } + if (WorkerPool == NULL) { + return QUIC_STATUS_INVALID_PARAMETER; + } - if (!CxPlatWorkersLazyStart(Config)) { + if (!CxPlatWorkerPoolLazyStart(WorkerPool, Config)) { Status = QUIC_STATUS_OUT_OF_MEMORY; goto Exit; } @@ -832,6 +836,7 @@ DataPathInitialize( if (TcpCallbacks) { Datapath->TcpHandlers = *TcpCallbacks; } + Datapath->WorkerPool = WorkerPool; if (Config && (Config->Flags & QUIC_EXECUTION_CONFIG_FLAG_QTIP)) { Datapath->UseTcp = TRUE; @@ -905,7 +910,7 @@ DataPathInitialize( Datapath->Partitions[i].Datapath = Datapath; Datapath->Partitions[i].PartitionIndex = (uint16_t)i; - Datapath->Partitions[i].EventQ = CxPlatWorkerGetEventQ(i); + Datapath->Partitions[i].EventQ = CxPlatWorkerPoolGetEventQ(Datapath->WorkerPool, i); CxPlatRefInitialize(&Datapath->Partitions[i].RefCount); CxPlatPoolInitialize( @@ -957,7 +962,11 @@ DataPathInitialize( FALSE, RecvDatagramLength, QUIC_POOL_DATA, - &Datapath->Partitions[i].RecvDatagramPool); + &Datapath->Partitions[i].RecvDatagramPool.Base); + CxPlatAddDynamicPoolAllocator( + Datapath->WorkerPool, + &Datapath->Partitions[i].RecvDatagramPool, + i); CxPlatPoolInitializeEx( FALSE, @@ -969,7 +978,7 @@ DataPathInitialize( &Datapath->Partitions[i].RioRecvPool); } - CXPLAT_FRE_ASSERT(CxPlatRundownAcquire(&CxPlatWorkerRundown)); + CXPLAT_FRE_ASSERT(CxPlatRundownAcquire(&WorkerPool->Rundown)); *NewDatapath = Datapath; Status = QUIC_STATUS_SUCCESS; @@ -999,9 +1008,9 @@ CxPlatDataPathRelease( CXPLAT_DBG_ASSERT(!Datapath->Freed); CXPLAT_DBG_ASSERT(Datapath->Uninitialized); Datapath->Freed = TRUE; - CXPLAT_FREE(Datapath, QUIC_POOL_DATAPATH); WSACleanup(); - CxPlatRundownRelease(&CxPlatWorkerRundown); + CxPlatRundownRelease(&Datapath->WorkerPool->Rundown); + CXPLAT_FREE(Datapath, QUIC_POOL_DATAPATH); } } @@ -1020,7 +1029,8 @@ CxPlatProcessorContextRelease( CxPlatPoolUninitialize(&DatapathProc->LargeSendBufferPool); CxPlatPoolUninitialize(&DatapathProc->RioSendBufferPool); CxPlatPoolUninitialize(&DatapathProc->RioLargeSendBufferPool); - CxPlatPoolUninitialize(&DatapathProc->RecvDatagramPool); + CxPlatRemoveDynamicPoolAllocator(&DatapathProc->RecvDatagramPool); + CxPlatPoolUninitialize(&DatapathProc->RecvDatagramPool.Base); CxPlatPoolUninitialize(&DatapathProc->RioRecvPool); CxPlatDataPathRelease(DatapathProc->Datapath); } @@ -1247,7 +1257,7 @@ SocketCreateUdp( goto Error; } - if (Config->RemoteAddress == NULL) { + if (Config->RemoteAddress == NULL && Datapath->PartitionCount > 1) { uint16_t Processor = i; // API only supports 16-bit proc index. Result = WSAIoctl( @@ -2465,7 +2475,7 @@ CxPlatSocketAllocRxIoBlock( if (SocketProc->Parent->UseRio) { OwningPool = &DatapathProc->RioRecvPool; } else { - OwningPool = &DatapathProc->RecvDatagramPool; + OwningPool = &DatapathProc->RecvDatagramPool.Base; } IoBlock = CxPlatPoolAlloc(OwningPool); @@ -2591,6 +2601,17 @@ CxPlatDataPathSocketProcessAcceptCompletion( SOCKET_PROCESSOR_AFFINITY RssAffinity = { 0 }; uint16_t PartitionIndex = 0; + ListenerSocketProc->AcceptSocket->LocalAddress = + *(const QUIC_ADDR*)ListenerSocketProc->AcceptAddrSpace; + ListenerSocketProc->AcceptSocket->RemoteAddress = + *(const QUIC_ADDR*)(ListenerSocketProc->AcceptAddrSpace + (sizeof(SOCKADDR_INET) + 16)); + CxPlatConvertFromMappedV6( + &ListenerSocketProc->AcceptSocket->LocalAddress, + &ListenerSocketProc->AcceptSocket->LocalAddress); + CxPlatConvertFromMappedV6( + &ListenerSocketProc->AcceptSocket->RemoteAddress, + &ListenerSocketProc->AcceptSocket->RemoteAddress); + QuicTraceEvent( DatapathErrorStatus, "[data][%p] ERROR, %u, %s.", @@ -2657,11 +2678,15 @@ CxPlatDataPathSocketProcessAcceptCompletion( goto Error; } - Datapath->TcpHandlers.Accept( + QUIC_STATUS Status = Datapath->TcpHandlers.Accept( ListenerSocketProc->Parent, ListenerSocketProc->Parent->ClientContext, ListenerSocketProc->AcceptSocket, &ListenerSocketProc->AcceptSocket->ClientContext); + if (QUIC_FAILED(Status)) { + goto Error; + } + ListenerSocketProc->AcceptSocket = NULL; AcceptSocketProc->IoStarted = TRUE; @@ -3987,7 +4012,7 @@ CxPlatSendDataComplete( _In_ ULONG IoResult ) { - const CXPLAT_SOCKET_PROC* SocketProc = SendData->SocketProc; + CXPLAT_SOCKET_PROC* SocketProc = SendData->SocketProc; if (IoResult != QUIC_STATUS_SUCCESS) { QuicTraceEvent( @@ -3999,18 +4024,21 @@ CxPlatSendDataComplete( } if (SocketProc->Parent->Type != CXPLAT_SOCKET_UDP) { - SocketProc->Parent->Datapath->TcpHandlers.SendComplete( - SocketProc->Parent, - SocketProc->Parent->ClientContext, - IoResult, - SendData->TotalSize); + if (CxPlatRundownAcquire(&SocketProc->RundownRef)) { + SocketProc->Parent->Datapath->TcpHandlers.SendComplete( + SocketProc->Parent, + SocketProc->Parent->ClientContext, + IoResult, + SendData->TotalSize); + CxPlatRundownRelease(&SocketProc->RundownRef); + } } SendDataFree(SendData); } _IRQL_requires_max_(DISPATCH_LEVEL) -QUIC_STATUS +void CxPlatSocketSendWithRio( _In_ CXPLAT_SEND_DATA* SendData, _In_ WSAMSG* WSAMhdr @@ -4063,18 +4091,16 @@ CxPlatSocketSendWithRio( WsaError, "RIOSendEx"); SendDataFree(SendData); - return HRESULT_FROM_WIN32(WsaError); + return; } SocketProc->RioSendCount++; CxPlatSocketArmRioNotify(SocketProc); } - - return QUIC_STATUS_SUCCESS; } _IRQL_requires_max_(DISPATCH_LEVEL) -QUIC_STATUS +void CxPlatSocketSendInline( _In_ const QUIC_ADDR* LocalAddress, _In_ CXPLAT_SEND_DATA* SendData @@ -4083,10 +4109,9 @@ CxPlatSocketSendInline( CXPLAT_SOCKET_PROC* SocketProc = SendData->SocketProc; if (SocketProc->RioSendCount == RIO_SEND_QUEUE_DEPTH) { CxPlatListInsertTail(&SocketProc->RioSendOverflow, &SendData->RioOverflowEntry); - return QUIC_STATUS_PENDING; + return; } - QUIC_STATUS Status; int Result; DWORD BytesSent; CXPLAT_DATAPATH* Datapath = SocketProc->Parent->Datapath; @@ -4171,7 +4196,8 @@ CxPlatSocketSendInline( } if (Socket->Type == CXPLAT_SOCKET_UDP && Socket->UseRio) { - return CxPlatSocketSendWithRio(SendData, &WSAMhdr); + CxPlatSocketSendWithRio(SendData, &WSAMhdr); + return; } // @@ -4205,11 +4231,8 @@ CxPlatSocketSendInline( if (Result == SOCKET_ERROR) { WsaError = WSAGetLastError(); if (WsaError == WSA_IO_PENDING) { - return QUIC_STATUS_SUCCESS; + return; } - Status = HRESULT_FROM_WIN32(WsaError); - } else { - Status = QUIC_STATUS_SUCCESS; } // @@ -4217,11 +4240,9 @@ CxPlatSocketSendInline( // CxPlatCancelDatapathIo(SocketProc, &SendData->Sqe); CxPlatSendDataComplete(SendData, WsaError); - - return Status; } -QUIC_STATUS +void CxPlatSocketSendEnqueue( _In_ const CXPLAT_ROUTE* Route, _In_ CXPLAT_SEND_DATA* SendData @@ -4234,11 +4255,10 @@ CxPlatSocketSendEnqueue( if (QUIC_FAILED(Status)) { CxPlatCancelDatapathIo(SendData->SocketProc, &SendData->Sqe); } - return Status; } _IRQL_requires_max_(DISPATCH_LEVEL) -QUIC_STATUS +void SocketSend( _In_ CXPLAT_SOCKET* Socket, _In_ const CXPLAT_ROUTE* Route, @@ -4262,21 +4282,18 @@ SocketSend( // // Currently RIO always queues sends. // - return CxPlatSocketSendEnqueue(Route, SendData); - } + CxPlatSocketSendEnqueue(Route, SendData); - if ((Socket->Type != CXPLAT_SOCKET_UDP) || + } else if ((Socket->Type != CXPLAT_SOCKET_UDP) || !(SendData->SendFlags & CXPLAT_SEND_FLAGS_MAX_THROUGHPUT)) { // // Currently TCP always sends inline. // - return - CxPlatSocketSendInline( - &Route->LocalAddress, - SendData); - } + CxPlatSocketSendInline(&Route->LocalAddress, SendData); - return CxPlatSocketSendEnqueue(Route, SendData); + } else { + CxPlatSocketSendEnqueue(Route, SendData); + } } void diff --git a/src/platform/datapath_xplat.c b/src/platform/datapath_xplat.c index e265e8e624..308a36df91 100644 --- a/src/platform/datapath_xplat.c +++ b/src/platform/datapath_xplat.c @@ -21,6 +21,7 @@ CxPlatDataPathInitialize( _In_ uint32_t ClientRecvContextLength, _In_opt_ const CXPLAT_UDP_DATAPATH_CALLBACKS* UdpCallbacks, _In_opt_ const CXPLAT_TCP_DATAPATH_CALLBACKS* TcpCallbacks, + _In_ CXPLAT_WORKER_POOL* WorkerPool, _In_opt_ QUIC_EXECUTION_CONFIG* Config, _Out_ CXPLAT_DATAPATH** NewDataPath ) @@ -36,6 +37,7 @@ CxPlatDataPathInitialize( ClientRecvContextLength, UdpCallbacks, TcpCallbacks, + WorkerPool, Config, NewDataPath); if (QUIC_FAILED(Status)) { @@ -51,13 +53,15 @@ CxPlatDataPathInitialize( ClientRecvContextLength, Config, (*NewDataPath), + WorkerPool, &((*NewDataPath)->RawDataPath)); if (QUIC_FAILED(Status)) { QuicTraceLogVerbose( RawDatapathInitFail, "[ raw] Failed to initialize raw datapath, status:%d", Status); - Status = QUIC_STATUS_SUCCESS; (*NewDataPath)->RawDataPath = NULL; + CxPlatDataPathUninitialize(*NewDataPath); + *NewDataPath = NULL; } } @@ -247,6 +251,15 @@ CxPlatSocketGetRemoteAddress( *Address = Socket->RemoteAddress; } +_IRQL_requires_max_(DISPATCH_LEVEL) +BOOLEAN +CxPlatSocketRawSocketAvailable( + _In_ CXPLAT_SOCKET* Socket + ) +{ + return Socket->RawSocketAvailable; +} + _IRQL_requires_max_(DISPATCH_LEVEL) void CxPlatRecvDataReturn( @@ -340,18 +353,19 @@ CxPlatSendDataIsFull( } _IRQL_requires_max_(DISPATCH_LEVEL) -QUIC_STATUS +void CxPlatSocketSend( _In_ CXPLAT_SOCKET* Socket, _In_ const CXPLAT_ROUTE* Route, _In_ CXPLAT_SEND_DATA* SendData ) { - CXPLAT_DBG_ASSERT( - DatapathType(SendData) == CXPLAT_DATAPATH_TYPE_USER || - DatapathType(SendData) == CXPLAT_DATAPATH_TYPE_RAW); - return DatapathType(SendData) == CXPLAT_DATAPATH_TYPE_USER ? - SocketSend(Socket, Route, SendData) : RawSocketSend(CxPlatSocketToRaw(Socket), Route, SendData); + if (DatapathType(SendData) == CXPLAT_DATAPATH_TYPE_USER) { + SocketSend(Socket, Route, SendData); + } else { + CXPLAT_DBG_ASSERT(DatapathType(SendData) == CXPLAT_DATAPATH_TYPE_RAW); + RawSocketSend(CxPlatSocketToRaw(Socket), Route, SendData); + } } _IRQL_requires_max_(PASSIVE_LEVEL) diff --git a/src/platform/inline.c b/src/platform/inline.c index e7d09525a9..6b4d075bda 100644 --- a/src/platform/inline.c +++ b/src/platform/inline.c @@ -55,6 +55,11 @@ CxPlatPoolFree( _In_ void* Entry ); +BOOLEAN +CxPlatPoolPrune( + _Inout_ CXPLAT_POOL* Pool + ); + void CxPlatListInitializeHead( _Out_ CXPLAT_LIST_ENTRY* ListHead diff --git a/src/platform/pcp.c b/src/platform/pcp.c index 41307eed33..b91e6a54f6 100644 --- a/src/platform/pcp.c +++ b/src/platform/pcp.c @@ -424,14 +424,7 @@ CxPlatPcpSendMapRequestInternal( Request->MAP.SuggestedExternalIpAddress, sizeof(Request->MAP.SuggestedExternalIpAddress)); - QUIC_STATUS Status = - CxPlatSocketSend( - Socket, - &Route, - SendData); - if (QUIC_FAILED(Status)) { - return Status; - } + CxPlatSocketSend(Socket, &Route, SendData); return QUIC_STATUS_SUCCESS; } @@ -528,14 +521,7 @@ CxPlatPcpSendPeerRequestInternal( sizeof(Request->PEER.RemotePeerIpAddress)); Request->PEER.RemotePeerPort = RemotePeerMappedAddress.Ipv6.sin6_port; - QUIC_STATUS Status = - CxPlatSocketSend( - Socket, - &Route, - SendData); - if (QUIC_FAILED(Status)) { - return Status; - } + CxPlatSocketSend(Socket, &Route, SendData); return QUIC_STATUS_SUCCESS; } diff --git a/src/platform/platform_internal.h b/src/platform/platform_internal.h index 6e4675eb14..be58ef523d 100644 --- a/src/platform/platform_internal.h +++ b/src/platform/platform_internal.h @@ -56,6 +56,11 @@ typedef struct CXPLAT_DATAPATH_COMMON { // The TCP callback function pointers. // CXPLAT_TCP_DATAPATH_CALLBACKS TcpHandlers; + + // + // The Worker WorkerPool + // + CXPLAT_WORKER_POOL* WorkerPool; } CXPLAT_DATAPATH_COMMON; typedef struct CXPLAT_SOCKET_COMMON { @@ -260,7 +265,7 @@ typedef struct QUIC_CACHEALIGN CXPLAT_DATAPATH_PROC { // Pool of receive datagram contexts and buffers to be shared by all sockets // on this core. // - CXPLAT_POOL RecvDatagramPool; + CXPLAT_POOL_EX RecvDatagramPool; // // Pool of RIO receive datagram contexts and buffers to be shared by all @@ -643,25 +648,17 @@ CxPlatCryptUninitialize( // // Platform Worker APIs -// - -void -CxPlatWorkersInit( - void - ); - -void -CxPlatWorkersUninit( - void - ); +// BOOLEAN -CxPlatWorkersLazyStart( +CxPlatWorkerPoolLazyStart( + _In_ CXPLAT_WORKER_POOL* WorkerPool, _In_opt_ QUIC_EXECUTION_CONFIG* Config ); CXPLAT_EVENTQ* -CxPlatWorkerGetEventQ( +CxPlatWorkerPoolGetEventQ( + _In_ const CXPLAT_WORKER_POOL* WorkerPool, _In_ uint16_t Index // Into the config processor array ); @@ -695,8 +692,6 @@ CxPlatDpRawGetDatapathSize( #define CXPLAT_CQE_TYPE_XDP_IO CXPLAT_CQE_TYPE_QUIC_BASE + 7 #define CXPLAT_CQE_TYPE_XDP_FLUSH_TX CXPLAT_CQE_TYPE_QUIC_BASE + 8 -extern CXPLAT_RUNDOWN_REF CxPlatWorkerRundown; - #if defined(CX_PLATFORM_LINUX) typedef struct CXPLAT_DATAPATH_PARTITION CXPLAT_DATAPATH_PARTITION; @@ -1005,6 +1000,7 @@ DataPathInitialize( _In_ uint32_t ClientRecvDataLength, _In_opt_ const CXPLAT_UDP_DATAPATH_CALLBACKS* UdpCallbacks, _In_opt_ const CXPLAT_TCP_DATAPATH_CALLBACKS* TcpCallbacks, + _In_ CXPLAT_WORKER_POOL* WorkerPool, _In_opt_ QUIC_EXECUTION_CONFIG* Config, _Out_ CXPLAT_DATAPATH** NewDatapath ); @@ -1076,7 +1072,7 @@ SendDataIsFull( ); _IRQL_requires_max_(DISPATCH_LEVEL) -QUIC_STATUS +void SocketSend( _In_ CXPLAT_SOCKET* Socket, _In_ const CXPLAT_ROUTE* Route, @@ -1121,6 +1117,7 @@ RawDataPathInitialize( _In_ uint32_t ClientRecvContextLength, _In_opt_ QUIC_EXECUTION_CONFIG* Config, _In_opt_ const CXPLAT_DATAPATH* ParentDataPath, + _In_ CXPLAT_WORKER_POOL* WorkerPool, _Out_ CXPLAT_DATAPATH_RAW** DataPath ); diff --git a/src/platform/platform_posix.c b/src/platform/platform_posix.c index 0e3c7c5eb1..6dd192e222 100644 --- a/src/platform/platform_posix.c +++ b/src/platform/platform_posix.c @@ -56,7 +56,7 @@ uint32_t CxPlatProcessorCount; uint64_t CxPlatTotalMemory; #if __APPLE__ || __FreeBSD__ -long CxPlatCurrentSqe = 0x80000000; +uintptr_t CxPlatCurrentSqe = 0x80000000; #endif #ifdef __clang__ @@ -245,8 +245,6 @@ CxPlatInitialize( return Status; } - CxPlatWorkersInit(); - CxPlatTotalMemory = CGroupGetMemoryLimit(); QuicTraceLogInfo( @@ -262,7 +260,6 @@ CxPlatUninitialize( void ) { - CxPlatWorkersUninit(); CxPlatCryptUninitialize(); close(RandomFd); QuicTraceLogInfo( @@ -441,7 +438,7 @@ CxPlatTimespecToUs( _In_ const struct timespec *Time ) { - return (Time->tv_sec * CXPLAT_MICROSEC_PER_SEC) + (Time->tv_nsec / CXPLAT_NANOSEC_PER_MICROSEC); + return ((uint64_t)Time->tv_sec * CXPLAT_MICROSEC_PER_SEC) + ((uint64_t)Time->tv_nsec / CXPLAT_NANOSEC_PER_MICROSEC); } uint64_t diff --git a/src/platform/platform_winuser.c b/src/platform/platform_winuser.c index bc8267297d..46e87aa35b 100644 --- a/src/platform/platform_winuser.c +++ b/src/platform/platform_winuser.c @@ -176,10 +176,11 @@ CxPlatProcessorInfoInit( if (Proc >= CxPlatProcessorGroupInfo[Group].Offset && Proc < CxPlatProcessorGroupInfo[Group].Offset + Info->Group.GroupInfo[Group].ActiveProcessorCount) { CxPlatProcessorInfo[Proc].Group = Group; - CxPlatProcessorInfo[Proc].Index = (Proc - CxPlatProcessorGroupInfo[Group].Offset); + CXPLAT_DBG_ASSERT(Proc - CxPlatProcessorGroupInfo[Group].Offset <= UINT8_MAX); + CxPlatProcessorInfo[Proc].Index = (uint8_t)(Proc - CxPlatProcessorGroupInfo[Group].Offset); QuicTraceLogInfo( - ProcessorInfoV2, - "[ dll] Proc[%u] Group[%hu] Index[%u] Active=%hhu", + ProcessorInfoV3, + "[ dll] Proc[%u] Group[%hu] Index[%hhu] Active=%hhu", Proc, (uint16_t)Group, CxPlatProcessorInfo[Proc].Index, @@ -294,8 +295,6 @@ CxPlatInitialize( } CryptoInitialized = TRUE; - CxPlatWorkersInit(); - #ifdef TIMERR_NOERROR QuicTraceLogInfo( WindowsUserInitialized2, @@ -334,7 +333,6 @@ CxPlatUninitialize( void ) { - CxPlatWorkersUninit(); CxPlatCryptUninitialize(); CXPLAT_DBG_ASSERT(CxPlatform.Heap); #ifdef TIMERR_NOERROR @@ -612,6 +610,118 @@ CxPlatGetAllocFailDenominator( } #endif +QUIC_STATUS +CxPlatThreadCreate( + _In_ CXPLAT_THREAD_CONFIG* Config, + _Out_ CXPLAT_THREAD* Thread + ) +{ +#ifdef CXPLAT_USE_CUSTOM_THREAD_CONTEXT + CXPLAT_THREAD_CUSTOM_CONTEXT* CustomContext = + CXPLAT_ALLOC_NONPAGED(sizeof(CXPLAT_THREAD_CUSTOM_CONTEXT), QUIC_POOL_CUSTOM_THREAD); + if (CustomContext == NULL) { + QuicTraceEvent( + AllocFailure, + "Allocation of '%s' failed. (%llu bytes)", + "Custom thread context", + sizeof(CXPLAT_THREAD_CUSTOM_CONTEXT)); + return QUIC_STATUS_OUT_OF_MEMORY; + } + CustomContext->Callback = Config->Callback; + CustomContext->Context = Config->Context; + *Thread = + CreateThread( + NULL, + 0, + CxPlatThreadCustomStart, + CustomContext, + 0, + NULL); + if (*Thread == NULL) { + CXPLAT_FREE(CustomContext, QUIC_POOL_CUSTOM_THREAD); + DWORD Error = GetLastError(); + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Error, + "CreateThread"); + return Error; + } +#else // CXPLAT_USE_CUSTOM_THREAD_CONTEXT + *Thread = + CreateThread( + NULL, + 0, + Config->Callback, + Config->Context, + 0, + NULL); + if (*Thread == NULL) { + DWORD Error = GetLastError(); + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + Error, + "CreateThread"); + return Error; + } +#endif // CXPLAT_USE_CUSTOM_THREAD_CONTEXT + CXPLAT_DBG_ASSERT(Config->IdealProcessor < CxPlatProcCount()); + const CXPLAT_PROCESSOR_INFO* ProcInfo = &CxPlatProcessorInfo[Config->IdealProcessor]; + GROUP_AFFINITY Group = {0}; + if (Config->Flags & CXPLAT_THREAD_FLAG_SET_AFFINITIZE) { + Group.Mask = (KAFFINITY)(1ull << ProcInfo->Index); // Fixed processor + } else { + Group.Mask = CxPlatProcessorGroupInfo[ProcInfo->Group].Mask; + } + Group.Group = ProcInfo->Group; + if (!SetThreadGroupAffinity(*Thread, &Group, NULL)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + GetLastError(), + "SetThreadGroupAffinity"); + } + if (Config->Flags & CXPLAT_THREAD_FLAG_SET_IDEAL_PROC && + !SetThreadIdealProcessorEx(*Thread, (PROCESSOR_NUMBER*)ProcInfo, NULL)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + GetLastError(), + "SetThreadIdealProcessorEx"); + } + if (Config->Flags & CXPLAT_THREAD_FLAG_HIGH_PRIORITY && + !SetThreadPriority(*Thread, THREAD_PRIORITY_HIGHEST)) { + QuicTraceEvent( + LibraryErrorStatus, + "[ lib] ERROR, %u, %s.", + GetLastError(), + "SetThreadPriority"); + } + if (Config->Name) { + WCHAR WideName[64] = L""; + size_t WideNameLength; + mbstowcs_s( + &WideNameLength, + WideName, + ARRAYSIZE(WideName) - 1, + Config->Name, + _TRUNCATE); +#if defined(QUIC_RESTRICTED_BUILD) + SetThreadDescription(*Thread, WideName); +#else + THREAD_NAME_INFORMATION_PRIVATE ThreadNameInfo; + RtlInitUnicodeString(&ThreadNameInfo.ThreadName, WideName); + NtSetInformationThread( + *Thread, + ThreadNameInformationPrivate, + &ThreadNameInfo, + sizeof(ThreadNameInfo)); +#endif + } + return QUIC_STATUS_SUCCESS; +} + #ifdef QUIC_EVENTS_MANIFEST_ETW _IRQL_requires_max_(PASSIVE_LEVEL) _IRQL_requires_same_ diff --git a/src/platform/platform_worker.c b/src/platform/platform_worker.c index 9ea1ac620c..00b7937cfa 100644 --- a/src/platform/platform_worker.c +++ b/src/platform/platform_worker.c @@ -52,6 +52,11 @@ typedef struct QUIC_CACHEALIGN CXPLAT_WORKER { // CXPLAT_LOCK ECLock; + // + // List of dynamic pools to manage. + // + CXPLAT_LIST_ENTRY DynamicPoolList; + // // Execution contexts that are waiting to be added to CXPLAT_WORKER::ExecutionContexts. // @@ -99,224 +104,303 @@ typedef struct QUIC_CACHEALIGN CXPLAT_WORKER { } CXPLAT_WORKER; -CXPLAT_LOCK CxPlatWorkerLock; -CXPLAT_RUNDOWN_REF CxPlatWorkerRundown; -uint32_t CxPlatWorkerCount; -CXPLAT_WORKER* CxPlatWorkers; CXPLAT_THREAD_CALLBACK(CxPlatWorkerThread, Context); void -CxPlatWorkersInit( - void +CxPlatWorkerPoolInit( + _In_ CXPLAT_WORKER_POOL* WorkerPool ) { - CxPlatLockInitialize(&CxPlatWorkerLock); + CXPLAT_DBG_ASSERT(WorkerPool); + CxPlatZeroMemory(WorkerPool, sizeof(*WorkerPool)); + CxPlatLockInitialize(&WorkerPool->WorkerLock); } #pragma warning(push) #pragma warning(disable:6385) #pragma warning(disable:6386) // SAL is confused about the worker size BOOLEAN -CxPlatWorkersLazyStart( +CxPlatWorkerPoolLazyStart( + _In_ CXPLAT_WORKER_POOL* WorkerPool, _In_opt_ QUIC_EXECUTION_CONFIG* Config ) { - CxPlatLockAcquire(&CxPlatWorkerLock); - if (CxPlatWorkers != NULL) { - CxPlatLockRelease(&CxPlatWorkerLock); + CXPLAT_DBG_ASSERT(WorkerPool); + CxPlatLockAcquire(&WorkerPool->WorkerLock); + if (WorkerPool->Workers != NULL) { + CxPlatLockRelease(&WorkerPool->WorkerLock); return TRUE; } const uint16_t* ProcessorList; if (Config && Config->ProcessorCount) { - CxPlatWorkerCount = Config->ProcessorCount; + WorkerPool->WorkerCount = Config->ProcessorCount; ProcessorList = Config->ProcessorList; } else { - CxPlatWorkerCount = CxPlatProcCount(); + WorkerPool->WorkerCount = CxPlatProcCount(); ProcessorList = NULL; } - CXPLAT_DBG_ASSERT(CxPlatWorkerCount > 0 && CxPlatWorkerCount <= UINT16_MAX); + CXPLAT_DBG_ASSERT(WorkerPool->WorkerCount > 0 && WorkerPool->WorkerCount <= UINT16_MAX); - const size_t WorkersSize = sizeof(CXPLAT_WORKER) * CxPlatWorkerCount; - CxPlatWorkers = (CXPLAT_WORKER*)CXPLAT_ALLOC_PAGED(WorkersSize, QUIC_POOL_PLATFORM_WORKER); - if (CxPlatWorkers == NULL) { + const size_t WorkersSize = sizeof(CXPLAT_WORKER) * WorkerPool->WorkerCount; + WorkerPool->Workers = (CXPLAT_WORKER*)CXPLAT_ALLOC_PAGED(WorkersSize, QUIC_POOL_PLATFORM_WORKER); + if (WorkerPool->Workers == NULL) { QuicTraceEvent( AllocFailure, "Allocation of '%s' failed. (%llu bytes)", "CXPLAT_WORKER", WorkersSize); - CxPlatWorkerCount = 0; + WorkerPool->WorkerCount = 0; goto Error; } + uint16_t ThreadFlags = CXPLAT_THREAD_FLAG_SET_IDEAL_PROC; + if (Config) { + if (Config->Flags & QUIC_EXECUTION_CONFIG_FLAG_NO_IDEAL_PROC) { + ThreadFlags &= ~CXPLAT_THREAD_FLAG_SET_IDEAL_PROC; // Remove the flag + } + if (Config->Flags & QUIC_EXECUTION_CONFIG_FLAG_HIGH_PRIORITY) { + ThreadFlags |= CXPLAT_THREAD_FLAG_HIGH_PRIORITY; + } + } + CXPLAT_THREAD_CONFIG ThreadConfig = { - CXPLAT_THREAD_FLAG_SET_IDEAL_PROC, + ThreadFlags, 0, "cxplat_worker", CxPlatWorkerThread, NULL }; - CxPlatZeroMemory(CxPlatWorkers, WorkersSize); - for (uint32_t i = 0; i < CxPlatWorkerCount; ++i) { - CxPlatLockInitialize(&CxPlatWorkers[i].ECLock); - CxPlatWorkers[i].InitializedECLock = TRUE; - CxPlatWorkers[i].IdealProcessor = ProcessorList ? ProcessorList[i] : (uint16_t)i; - CXPLAT_DBG_ASSERT(CxPlatWorkers[i].IdealProcessor < CxPlatProcCount()); - ThreadConfig.IdealProcessor = CxPlatWorkers[i].IdealProcessor; - ThreadConfig.Context = &CxPlatWorkers[i]; - if (!CxPlatEventQInitialize(&CxPlatWorkers[i].EventQ)) { + CxPlatZeroMemory(WorkerPool->Workers, WorkersSize); + for (uint32_t i = 0; i < WorkerPool->WorkerCount; ++i) { + CxPlatLockInitialize(&WorkerPool->Workers[i].ECLock); + CxPlatListInitializeHead(&WorkerPool->Workers[i].DynamicPoolList); + WorkerPool->Workers[i].InitializedECLock = TRUE; + WorkerPool->Workers[i].IdealProcessor = ProcessorList ? ProcessorList[i] : (uint16_t)i; + CXPLAT_DBG_ASSERT(WorkerPool->Workers[i].IdealProcessor < CxPlatProcCount()); + ThreadConfig.IdealProcessor = WorkerPool->Workers[i].IdealProcessor; + ThreadConfig.Context = &WorkerPool->Workers[i]; + if (!CxPlatEventQInitialize(&WorkerPool->Workers[i].EventQ)) { QuicTraceEvent( LibraryError, "[ lib] ERROR, %s.", "CxPlatEventQInitialize"); goto Error; } - CxPlatWorkers[i].InitializedEventQ = TRUE; + WorkerPool->Workers[i].InitializedEventQ = TRUE; #ifdef CXPLAT_SQE_INIT - CxPlatWorkers[i].ShutdownSqe = (CXPLAT_SQE)CxPlatWorkers[i].EventQ; - if (!CxPlatSqeInitialize(&CxPlatWorkers[i].EventQ, &CxPlatWorkers[i].ShutdownSqe, NULL)) { + WorkerPool->Workers[i].ShutdownSqe = (CXPLAT_SQE)WorkerPool->Workers[i].EventQ; + if (!CxPlatSqeInitialize(&WorkerPool->Workers[i].EventQ, &WorkerPool->Workers[i].ShutdownSqe, NULL)) { QuicTraceEvent( LibraryError, "[ lib] ERROR, %s.", "CxPlatSqeInitialize(shutdown)"); goto Error; } - CxPlatWorkers[i].InitializedShutdownSqe = TRUE; - CxPlatWorkers[i].WakeSqe = (CXPLAT_SQE)WorkerWakeEventPayload; - if (!CxPlatSqeInitialize(&CxPlatWorkers[i].EventQ, &CxPlatWorkers[i].WakeSqe, (void*)&WorkerWakeEventPayload)) { + WorkerPool->Workers[i].InitializedShutdownSqe = TRUE; + WorkerPool->Workers[i].WakeSqe = (CXPLAT_SQE)WorkerWakeEventPayload; + if (!CxPlatSqeInitialize(&WorkerPool->Workers[i].EventQ, &WorkerPool->Workers[i].WakeSqe, (void*)&WorkerWakeEventPayload)) { QuicTraceEvent( LibraryError, "[ lib] ERROR, %s.", "CxPlatSqeInitialize(wake)"); goto Error; } - CxPlatWorkers[i].InitializedWakeSqe = TRUE; - CxPlatWorkers[i].UpdatePollSqe = (CXPLAT_SQE)WorkerUpdatePollEventPayload; - if (!CxPlatSqeInitialize(&CxPlatWorkers[i].EventQ, &CxPlatWorkers[i].UpdatePollSqe, (void*)&WorkerUpdatePollEventPayload)) { + WorkerPool->Workers[i].InitializedWakeSqe = TRUE; + WorkerPool->Workers[i].UpdatePollSqe = (CXPLAT_SQE)WorkerUpdatePollEventPayload; + if (!CxPlatSqeInitialize(&WorkerPool->Workers[i].EventQ, &WorkerPool->Workers[i].UpdatePollSqe, (void*)&WorkerUpdatePollEventPayload)) { QuicTraceEvent( LibraryError, "[ lib] ERROR, %s.", "CxPlatSqeInitialize(updatepoll)"); goto Error; } - CxPlatWorkers[i].InitializedUpdatePollSqe = TRUE; + WorkerPool->Workers[i].InitializedUpdatePollSqe = TRUE; #endif if (QUIC_FAILED( - CxPlatThreadCreate(&ThreadConfig, &CxPlatWorkers[i].Thread))) { + CxPlatThreadCreate(&ThreadConfig, &WorkerPool->Workers[i].Thread))) { goto Error; } - CxPlatWorkers[i].InitializedThread = TRUE; + WorkerPool->Workers[i].InitializedThread = TRUE; } - CxPlatRundownInitialize(&CxPlatWorkerRundown); + CxPlatRundownInitialize(&WorkerPool->Rundown); - CxPlatLockRelease(&CxPlatWorkerLock); + CxPlatLockRelease(&WorkerPool->WorkerLock); return TRUE; Error: - if (CxPlatWorkers) { - for (uint32_t i = 0; i < CxPlatWorkerCount; ++i) { - if (CxPlatWorkers[i].InitializedThread) { - CxPlatWorkers[i].StoppingThread = TRUE; + if (WorkerPool->Workers) { + for (uint32_t i = 0; i < WorkerPool->WorkerCount; ++i) { + if (WorkerPool->Workers[i].InitializedThread) { + WorkerPool->Workers[i].StoppingThread = TRUE; CxPlatEventQEnqueue( - &CxPlatWorkers[i].EventQ, - &CxPlatWorkers[i].ShutdownSqe, + &WorkerPool->Workers[i].EventQ, + &WorkerPool->Workers[i].ShutdownSqe, NULL); - CxPlatThreadWait(&CxPlatWorkers[i].Thread); - CxPlatThreadDelete(&CxPlatWorkers[i].Thread); + CxPlatThreadWait(&WorkerPool->Workers[i].Thread); + CxPlatThreadDelete(&WorkerPool->Workers[i].Thread); #if DEBUG - CXPLAT_DBG_ASSERT(CxPlatWorkers[i].ThreadStarted); - CXPLAT_DBG_ASSERT(CxPlatWorkers[i].ThreadFinished); + CXPLAT_DBG_ASSERT(WorkerPool->Workers[i].ThreadStarted); + CXPLAT_DBG_ASSERT(WorkerPool->Workers[i].ThreadFinished); #endif - CxPlatWorkers[i].DestroyedThread = TRUE; + WorkerPool->Workers[i].DestroyedThread = TRUE; } #ifdef CXPLAT_SQE_INIT - if (CxPlatWorkers[i].InitializedUpdatePollSqe) { - CxPlatSqeCleanup(&CxPlatWorkers[i].EventQ, &CxPlatWorkers[i].UpdatePollSqe); + if (WorkerPool->Workers[i].InitializedUpdatePollSqe) { + CxPlatSqeCleanup(&WorkerPool->Workers[i].EventQ, &WorkerPool->Workers[i].UpdatePollSqe); } - if (CxPlatWorkers[i].InitializedWakeSqe) { - CxPlatSqeCleanup(&CxPlatWorkers[i].EventQ, &CxPlatWorkers[i].WakeSqe); + if (WorkerPool->Workers[i].InitializedWakeSqe) { + CxPlatSqeCleanup(&WorkerPool->Workers[i].EventQ, &WorkerPool->Workers[i].WakeSqe); } - if (CxPlatWorkers[i].InitializedShutdownSqe) { - CxPlatSqeCleanup(&CxPlatWorkers[i].EventQ, &CxPlatWorkers[i].ShutdownSqe); + if (WorkerPool->Workers[i].InitializedShutdownSqe) { + CxPlatSqeCleanup(&WorkerPool->Workers[i].EventQ, &WorkerPool->Workers[i].ShutdownSqe); } #endif // CXPLAT_SQE_INIT - if (CxPlatWorkers[i].InitializedEventQ) { - CxPlatEventQCleanup(&CxPlatWorkers[i].EventQ); + if (WorkerPool->Workers[i].InitializedEventQ) { + CxPlatEventQCleanup(&WorkerPool->Workers[i].EventQ); } - if (CxPlatWorkers[i].InitializedECLock) { - CxPlatLockUninitialize(&CxPlatWorkers[i].ECLock); + if (WorkerPool->Workers[i].InitializedECLock) { + CxPlatLockUninitialize(&WorkerPool->Workers[i].ECLock); } } - CXPLAT_FREE(CxPlatWorkers, QUIC_POOL_PLATFORM_WORKER); - CxPlatWorkers = NULL; + CXPLAT_FREE(WorkerPool->Workers, QUIC_POOL_PLATFORM_WORKER); + WorkerPool->Workers = NULL; } - CxPlatLockRelease(&CxPlatWorkerLock); + CxPlatLockRelease(&WorkerPool->WorkerLock); return FALSE; } #pragma warning(pop) void -CxPlatWorkersUninit( - void +CxPlatWorkerPoolUninit( + _In_ CXPLAT_WORKER_POOL* WorkerPool ) { - if (CxPlatWorkers != NULL) { - CxPlatRundownReleaseAndWait(&CxPlatWorkerRundown); + CXPLAT_DBG_ASSERT(WorkerPool); + if (WorkerPool->Workers != NULL) { + CxPlatRundownReleaseAndWait(&WorkerPool->Rundown); - for (uint32_t i = 0; i < CxPlatWorkerCount; ++i) { - CxPlatWorkers[i].StoppingThread = TRUE; + for (uint32_t i = 0; i < WorkerPool->WorkerCount; ++i) { + WorkerPool->Workers[i].StoppingThread = TRUE; CxPlatEventQEnqueue( - &CxPlatWorkers[i].EventQ, - &CxPlatWorkers[i].ShutdownSqe, + &WorkerPool->Workers[i].EventQ, + &WorkerPool->Workers[i].ShutdownSqe, NULL); - CxPlatThreadWait(&CxPlatWorkers[i].Thread); - CxPlatThreadDelete(&CxPlatWorkers[i].Thread); + CxPlatThreadWait(&WorkerPool->Workers[i].Thread); + CxPlatThreadDelete(&WorkerPool->Workers[i].Thread); #if DEBUG - CXPLAT_DBG_ASSERT(CxPlatWorkers[i].ThreadStarted); - CXPLAT_DBG_ASSERT(CxPlatWorkers[i].ThreadFinished); + CXPLAT_DBG_ASSERT(WorkerPool->Workers[i].ThreadStarted); + CXPLAT_DBG_ASSERT(WorkerPool->Workers[i].ThreadFinished); #endif - CxPlatWorkers[i].DestroyedThread = TRUE; + WorkerPool->Workers[i].DestroyedThread = TRUE; #ifdef CXPLAT_SQE_INIT - CxPlatSqeCleanup(&CxPlatWorkers[i].EventQ, &CxPlatWorkers[i].UpdatePollSqe); - CxPlatSqeCleanup(&CxPlatWorkers[i].EventQ, &CxPlatWorkers[i].WakeSqe); - CxPlatSqeCleanup(&CxPlatWorkers[i].EventQ, &CxPlatWorkers[i].ShutdownSqe); + CxPlatSqeCleanup(&WorkerPool->Workers[i].EventQ, &WorkerPool->Workers[i].UpdatePollSqe); + CxPlatSqeCleanup(&WorkerPool->Workers[i].EventQ, &WorkerPool->Workers[i].WakeSqe); + CxPlatSqeCleanup(&WorkerPool->Workers[i].EventQ, &WorkerPool->Workers[i].ShutdownSqe); #endif // CXPLAT_SQE_INIT - CxPlatEventQCleanup(&CxPlatWorkers[i].EventQ); - CxPlatLockUninitialize(&CxPlatWorkers[i].ECLock); + CxPlatEventQCleanup(&WorkerPool->Workers[i].EventQ); + CXPLAT_DBG_ASSERT(CxPlatListIsEmpty(&WorkerPool->Workers[i].DynamicPoolList)); + CxPlatLockUninitialize(&WorkerPool->Workers[i].ECLock); } - CXPLAT_FREE(CxPlatWorkers, QUIC_POOL_PLATFORM_WORKER); - CxPlatWorkers = NULL; + CXPLAT_FREE(WorkerPool->Workers, QUIC_POOL_PLATFORM_WORKER); + WorkerPool->Workers = NULL; + + CxPlatRundownUninitialize(&WorkerPool->Rundown); + } + + CxPlatLockUninitialize(&WorkerPool->WorkerLock); +} + +#define DYNAMIC_POOL_PROCESSING_PERIOD 1000000 // 1 second +#define DYNAMIC_POOL_PRUNE_COUNT 8 + +void +CxPlatAddDynamicPoolAllocator( + _In_ CXPLAT_WORKER_POOL* WorkerPool, + _Inout_ CXPLAT_POOL_EX* Pool, + _In_ uint16_t Index // Into the execution config processor array + ) +{ + CXPLAT_DBG_ASSERT(WorkerPool); + CXPLAT_FRE_ASSERT(Index < WorkerPool->WorkerCount); + CXPLAT_WORKER* Worker = &WorkerPool->Workers[Index]; + Pool->Owner = Worker; + CxPlatLockAcquire(&Worker->ECLock); + CxPlatListInsertTail(&Worker->DynamicPoolList, &Pool->Link); + CxPlatLockRelease(&Worker->ECLock); +} + +void +CxPlatRemoveDynamicPoolAllocator( + _Inout_ CXPLAT_POOL_EX* Pool + ) +{ + CXPLAT_WORKER* Worker = (CXPLAT_WORKER*)Pool->Owner; + CxPlatLockAcquire(&Worker->ECLock); + CxPlatListEntryRemove(&Pool->Link); + CxPlatLockRelease(&Worker->ECLock); +} - CxPlatRundownUninitialize(&CxPlatWorkerRundown); +void +CxPlatProcessDynamicPoolAllocator( + _Inout_ CXPLAT_POOL_EX* Pool + ) +{ + for (uint32_t i = 0; i < DYNAMIC_POOL_PRUNE_COUNT; ++i) { + if (!CxPlatPoolPrune((CXPLAT_POOL*)Pool)) { + return; + } } +} - CxPlatLockUninitialize(&CxPlatWorkerLock); +void +CxPlatProcessDynamicPoolAllocators( + _In_ CXPLAT_WORKER* Worker + ) +{ + QuicTraceLogVerbose( + PlatformWorkerProcessPools, + "[ lib][%p] Processing pools", + Worker); + + CxPlatLockAcquire(&Worker->ECLock); + CXPLAT_LIST_ENTRY* Entry = Worker->DynamicPoolList.Flink; + while (Entry != &Worker->DynamicPoolList) { + CXPLAT_POOL_EX* Pool = CXPLAT_CONTAINING_RECORD(Entry, CXPLAT_POOL_EX, Link); + Entry = Entry->Flink; + CxPlatProcessDynamicPoolAllocator(Pool); + } + CxPlatLockRelease(&Worker->ECLock); } CXPLAT_EVENTQ* -CxPlatWorkerGetEventQ( +CxPlatWorkerPoolGetEventQ( + _In_ const CXPLAT_WORKER_POOL* WorkerPool, _In_ uint16_t Index ) { - CXPLAT_FRE_ASSERT(Index < CxPlatWorkerCount); - return &CxPlatWorkers[Index].EventQ; + CXPLAT_DBG_ASSERT(WorkerPool); + CXPLAT_FRE_ASSERT(Index < WorkerPool->WorkerCount); + return &WorkerPool->Workers[Index].EventQ; } void CxPlatAddExecutionContext( + _In_ CXPLAT_WORKER_POOL* WorkerPool, _Inout_ CXPLAT_EXECUTION_CONTEXT* Context, _In_ uint16_t Index ) { - CXPLAT_FRE_ASSERT(Index < CxPlatWorkerCount); - CXPLAT_WORKER* Worker = &CxPlatWorkers[Index]; + CXPLAT_DBG_ASSERT(WorkerPool); + CXPLAT_FRE_ASSERT(Index < WorkerPool->WorkerCount); + CXPLAT_WORKER* Worker = &WorkerPool->Workers[Index]; Context->CxPlatContext = Worker; CxPlatLockAcquire(&Worker->ECLock); @@ -379,7 +463,6 @@ CxPlatRunExecutionContexts( #if DEBUG // Debug statistics ++Worker->EcPollCount; #endif - State->TimeNow = CxPlatTimeUs64(); uint64_t NextTime = UINT64_MAX; CXPLAT_SLIST_ENTRY** EC = &Worker->ExecutionContexts; @@ -478,7 +561,7 @@ CXPLAT_THREAD_CALLBACK(CxPlatWorkerThread, Context) Worker->ThreadStarted = TRUE; #endif - CXPLAT_EXECUTION_STATE State = { 0, CxPlatTimeUs64(), UINT32_MAX, 0, CxPlatCurThreadID() }; + CXPLAT_EXECUTION_STATE State = { 0, 0, 0, UINT32_MAX, 0, CxPlatCurThreadID() }; Worker->Running = TRUE; @@ -488,9 +571,11 @@ CXPLAT_THREAD_CALLBACK(CxPlatWorkerThread, Context) #if DEBUG // Debug statistics ++Worker->LoopCount; #endif + State.TimeNow = CxPlatTimeUs64(); CxPlatRunExecutionContexts(Worker, &State); if (State.WaitTime && InterlockedFetchAndClearBoolean(&Worker->Running)) { + State.TimeNow = CxPlatTimeUs64(); CxPlatRunExecutionContexts(Worker, &State); // Run once more to handle race conditions } @@ -504,6 +589,11 @@ CXPLAT_THREAD_CALLBACK(CxPlatWorkerThread, Context) CxPlatSchedulerYield(); State.NoWorkCount = 0; } + + if (State.TimeNow - State.LastPoolProcessTime > DYNAMIC_POOL_PROCESSING_PERIOD) { + CxPlatProcessDynamicPoolAllocators(Worker); + State.LastPoolProcessTime = State.TimeNow; + } } Shutdown: diff --git a/src/platform/unittest/DataPathTest.cpp b/src/platform/unittest/DataPathTest.cpp index f639a51fc8..33906ba672 100644 --- a/src/platform/unittest/DataPathTest.cpp +++ b/src/platform/unittest/DataPathTest.cpp @@ -20,6 +20,7 @@ #endif extern bool UseDuoNic; +extern CXPLAT_WORKER_POOL WorkerPool; // // Connect to the duonic address (if using duonic) or localhost (if not). @@ -64,6 +65,7 @@ struct QuicAddr 0, NULL, NULL, + &WorkerPool, NULL, &Datapath))) { GTEST_FATAL_FAILURE_(" QuicDataPathInitialize failed."); @@ -115,8 +117,10 @@ struct TcpListenerContext { CXPLAT_SOCKET* Server; TcpClientContext ServerContext; bool Accepted : 1; + bool Reject : 1; + bool Rejected : 1; CXPLAT_EVENT AcceptEvent; - TcpListenerContext() : Server(nullptr), Accepted(false) { + TcpListenerContext() : Server(nullptr), Accepted(false), Reject{false}, Rejected{false} { CxPlatEventInitialize(&AcceptEvent, FALSE, FALSE); } ~TcpListenerContext() { @@ -300,11 +304,7 @@ struct DataPathTest : public ::testing::TestWithParam ASSERT_NE(nullptr, ServerBuffer); memcpy(ServerBuffer->Buffer, RecvData->Buffer, RecvData->BufferLength); - VERIFY_QUIC_SUCCESS( - CxPlatSocketSend( - Socket, - RecvData->Route, - ServerSendData)); + CxPlatSocketSend(Socket, RecvData->Route, ServerSendData); } else if (RecvData->Route->RemoteAddress.Ipv4.sin_port == RecvContext->DestinationAddress.Ipv4.sin_port) { CxPlatEventSet(RecvContext->ClientCompletion); @@ -319,7 +319,7 @@ struct DataPathTest : public ::testing::TestWithParam CxPlatRecvDataReturn(RecvDataChain); } - static void + static QUIC_STATUS EmptyAcceptCallback( _In_ CXPLAT_SOCKET* /* ListenerSocket */, _In_ void* /* ListenerContext */, @@ -327,6 +327,8 @@ struct DataPathTest : public ::testing::TestWithParam _Out_ void** /* ClientContext */ ) { + // If we somehow get a connection here, reject it + return QUIC_STATUS_CONNECTION_REFUSED; } static void @@ -338,7 +340,7 @@ struct DataPathTest : public ::testing::TestWithParam { } - static void + static QUIC_STATUS TcpAcceptCallback( _In_ CXPLAT_SOCKET* /* ListenerSocket */, _In_ void* Context, @@ -347,10 +349,16 @@ struct DataPathTest : public ::testing::TestWithParam ) { TcpListenerContext* ListenerContext = (TcpListenerContext*)Context; + if (ListenerContext->Reject) { + ListenerContext->Rejected = true; + CxPlatEventSet(ListenerContext->AcceptEvent); + return QUIC_STATUS_CONNECTION_REFUSED; + } ListenerContext->Server = ClientSocket; *ClientContext = &ListenerContext->ServerContext; ListenerContext->Accepted = true; CxPlatEventSet(ListenerContext->AcceptEvent); + return QUIC_STATUS_SUCCESS; } static void @@ -427,7 +435,7 @@ QuicAddr DataPathTest::UnspecIPv4; QuicAddr DataPathTest::UnspecIPv6; struct CxPlatDataPath { - QUIC_EXECUTION_CONFIG DefaultExecutionConfig { QUIC_EXECUTION_CONFIG_FLAG_XDP, 0, 0, {0} }; + QUIC_EXECUTION_CONFIG DefaultExecutionConfig { QUIC_EXECUTION_CONFIG_FLAG_NONE, 0, 0, {0} }; CXPLAT_DATAPATH* Datapath {nullptr}; QUIC_STATUS InitStatus; CxPlatDataPath( @@ -437,11 +445,15 @@ struct CxPlatDataPath { _In_opt_ QUIC_EXECUTION_CONFIG* Config = nullptr ) noexcept { + if (UseDuoNic && Config == nullptr) { + DefaultExecutionConfig.Flags = QUIC_EXECUTION_CONFIG_FLAG_XDP; + } InitStatus = CxPlatDataPathInitialize( ClientRecvContextLength, UdpCallbacks, TcpCallbacks, + &WorkerPool, Config ? Config : &DefaultExecutionConfig, &Datapath); } @@ -550,6 +562,7 @@ struct CxPlatSocket { // wait for an event set by ResolveRouteComplete. // EXPECT_EQ(InitStatus, QUIC_STATUS_SUCCESS); + EXPECT_TRUE(CxPlatSocketRawSocketAvailable(Socket)); } } } @@ -602,19 +615,15 @@ struct CxPlatSocket { QUIC_ADDR GetRemoteAddress() const noexcept { return Route.RemoteAddress; } - QUIC_STATUS + void Send( _In_ const CXPLAT_ROUTE& _Route, _In_ CXPLAT_SEND_DATA* SendData ) const noexcept { - return - CxPlatSocketSend( - Socket, - &_Route, - SendData); + CxPlatSocketSend(Socket, &_Route, SendData); } - QUIC_STATUS + void Send( _In_ const QUIC_ADDR& RemoteAddress, _In_ CXPLAT_SEND_DATA* SendData @@ -622,14 +631,14 @@ struct CxPlatSocket { { CXPLAT_ROUTE _Route = Route; _Route.RemoteAddress = RemoteAddress; - return Send(_Route, SendData); + Send(_Route, SendData); } - QUIC_STATUS + void Send( _In_ CXPLAT_SEND_DATA* SendData ) const noexcept { - return Send(Route, SendData); + Send(Route, SendData); } }; @@ -668,17 +677,18 @@ TEST_F(DataPathTest, Initialize) VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus()); ASSERT_NE(nullptr, Datapath.Datapath); } - { - QUIC_EXECUTION_CONFIG Config = { QUIC_EXECUTION_CONFIG_FLAG_NONE, 0, 1, {0} }; + if (UseDuoNic) { + QUIC_EXECUTION_CONFIG Config = { QUIC_EXECUTION_CONFIG_FLAG_XDP, 0, 1, {0} }; CxPlatDataPath Datapath(&EmptyUdpCallbacks, nullptr, 0, &Config); VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus()); ASSERT_NE(nullptr, Datapath.Datapath); + ASSERT_TRUE(Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_RAW)); } } TEST_F(DataPathTest, InitializeInvalid) { - ASSERT_EQ(QUIC_STATUS_INVALID_PARAMETER, CxPlatDataPathInitialize(0, nullptr, nullptr, nullptr, nullptr)); + ASSERT_EQ(QUIC_STATUS_INVALID_PARAMETER, CxPlatDataPathInitialize(0, nullptr, nullptr, nullptr, nullptr, nullptr)); { const CXPLAT_UDP_DATAPATH_CALLBACKS InvalidUdpCallbacks = { nullptr, EmptyUnreachableCallback }; CxPlatDataPath Datapath(&InvalidUdpCallbacks); @@ -793,7 +803,7 @@ TEST_P(DataPathTest, UdpData) ASSERT_NE(nullptr, ClientBuffer); memcpy(ClientBuffer->Buffer, ExpectedData, ExpectedDataSize); - VERIFY_QUIC_SUCCESS(Client.Send(ClientSendData)); + Client.Send(ClientSendData); ASSERT_TRUE(CxPlatEventWaitWithTimeout(RecvContext.ClientCompletion, 2000)); } @@ -830,7 +840,7 @@ TEST_P(DataPathTest, UdpDataPolling) ASSERT_NE(nullptr, ClientBuffer); memcpy(ClientBuffer->Buffer, ExpectedData, ExpectedDataSize); - VERIFY_QUIC_SUCCESS(Client.Send(ClientSendData)); + Client.Send(ClientSendData); ASSERT_TRUE(CxPlatEventWaitWithTimeout(RecvContext.ClientCompletion, 2000)); } @@ -867,7 +877,7 @@ TEST_P(DataPathTest, UdpDataRebind) ASSERT_NE(nullptr, ClientBuffer); memcpy(ClientBuffer->Buffer, ExpectedData, ExpectedDataSize); - VERIFY_QUIC_SUCCESS(Client.Send(ClientSendData)); + Client.Send(ClientSendData); ASSERT_TRUE(CxPlatEventWaitWithTimeout(RecvContext.ClientCompletion, 2000)); CxPlatEventReset(RecvContext.ClientCompletion); } @@ -884,7 +894,7 @@ TEST_P(DataPathTest, UdpDataRebind) ASSERT_NE(nullptr, ClientBuffer); memcpy(ClientBuffer->Buffer, ExpectedData, ExpectedDataSize); - VERIFY_QUIC_SUCCESS(Client.Send(ClientSendData)); + Client.Send(ClientSendData); ASSERT_TRUE(CxPlatEventWaitWithTimeout(RecvContext.ClientCompletion, 2000)); } } @@ -922,7 +932,7 @@ TEST_P(DataPathTest, UdpDataECT0) ASSERT_NE(nullptr, ClientBuffer); memcpy(ClientBuffer->Buffer, ExpectedData, ExpectedDataSize); - VERIFY_QUIC_SUCCESS(Client.Send(ClientSendData)); + Client.Send(ClientSendData); ASSERT_TRUE(CxPlatEventWaitWithTimeout(RecvContext.ClientCompletion, 2000)); } @@ -971,7 +981,7 @@ TEST_P(DataPathTest, UdpShareClientSocket) memcpy(ClientBuffer->Buffer, ExpectedData, ExpectedDataSize); RecvContext.DestinationAddress = Server1.GetLocalAddress(); - VERIFY_QUIC_SUCCESS(Client1.Send(ClientSendData)); + Client1.Send(ClientSendData); ASSERT_TRUE(CxPlatEventWaitWithTimeout(RecvContext.ClientCompletion, 2000)); CxPlatEventReset(RecvContext.ClientCompletion); @@ -983,7 +993,7 @@ TEST_P(DataPathTest, UdpShareClientSocket) memcpy(ClientBuffer->Buffer, ExpectedData, ExpectedDataSize); RecvContext.DestinationAddress = Server2.GetLocalAddress(); - VERIFY_QUIC_SUCCESS(Client2.Send(ClientSendData)); + Client2.Send(ClientSendData); ASSERT_TRUE(CxPlatEventWaitWithTimeout(RecvContext.ClientCompletion, 2000)); CxPlatEventReset(RecvContext.ClientCompletion); } @@ -1008,6 +1018,23 @@ TEST_P(DataPathTest, MultiBindListener) { ASSERT_EQ(QUIC_STATUS_ADDRESS_IN_USE, Server2.GetInitStatus()); } +TEST_P(DataPathTest, MultiBindListenerSingleProcessor) { + UdpRecvContext RecvContext; + QUIC_EXECUTION_CONFIG Config = { QUIC_EXECUTION_CONFIG_FLAG_NO_IDEAL_PROC, UINT32_MAX, 1, 0 }; + CxPlatDataPath Datapath(&UdpRecvCallbacks, nullptr, 0, &Config); + + auto ServerAddress = GetNewLocalAddr(); + CxPlatSocket Server1(Datapath, &ServerAddress.SockAddr, nullptr, &RecvContext); + while (Server1.GetInitStatus() == QUIC_STATUS_ADDRESS_IN_USE) { + ServerAddress.SockAddr.Ipv4.sin_port = GetNextPort(); + Server1.CreateUdp(Datapath, &ServerAddress.SockAddr, nullptr, &RecvContext); + } + VERIFY_QUIC_SUCCESS(Server1.GetInitStatus()); + + CxPlatSocket Server2(Datapath, &ServerAddress.SockAddr, nullptr, &RecvContext); + ASSERT_EQ(QUIC_STATUS_ADDRESS_IN_USE, Server2.GetInitStatus()); +} + TEST_F(DataPathTest, TcpListener) { CxPlatDataPath Datapath(nullptr, &EmptyTcpCallbacks); @@ -1054,12 +1081,56 @@ TEST_P(DataPathTest, TcpConnect) ASSERT_TRUE(CxPlatEventWaitWithTimeout(ClientContext.ConnectEvent, 500)); ASSERT_TRUE(CxPlatEventWaitWithTimeout(ListenerContext.AcceptEvent, 500)); ASSERT_NE(nullptr, ListenerContext.Server); + QUIC_ADDR ServerRemote = {}; + CxPlatSocketGetRemoteAddress(ListenerContext.Server, &ServerRemote); + QUIC_ADDR ServerLocal = {}; + CxPlatSocketGetLocalAddress(ListenerContext.Server, &ServerLocal); + ASSERT_NE(ServerRemote.Ipv4.sin_port, (uint16_t)0); + ASSERT_NE(ServerLocal.Ipv4.sin_port, (uint16_t)0); + ASSERT_EQ(ServerRemote.Ipv4.sin_port, Client.GetLocalAddress().Ipv4.sin_port); ListenerContext.DeleteSocket(); ASSERT_TRUE(CxPlatEventWaitWithTimeout(ClientContext.DisconnectEvent, 500)); } +TEST_P(DataPathTest, TcpRejectConnect) +{ + CxPlatDataPath Datapath(nullptr, &TcpRecvCallbacks); + if (!Datapath.IsSupported(CXPLAT_DATAPATH_FEATURE_TCP)) { + GTEST_SKIP_("TCP is not supported"); + } + VERIFY_QUIC_SUCCESS(Datapath.GetInitStatus()); + ASSERT_NE(nullptr, Datapath.Datapath); + + TcpListenerContext ListenerContext; + auto serverAddress = GetNewLocalAddr(); + CxPlatSocket Listener; Listener.CreateTcpListener(Datapath, &serverAddress.SockAddr, &ListenerContext); + while (Listener.GetInitStatus() == QUIC_STATUS_ADDRESS_IN_USE) { + serverAddress.SockAddr.Ipv4.sin_port = GetNextPort(); + Listener.CreateTcpListener(Datapath, &serverAddress.SockAddr, &ListenerContext); + } + VERIFY_QUIC_SUCCESS(Listener.GetInitStatus()); + ASSERT_NE(nullptr, Listener.Socket); + serverAddress.SockAddr = Listener.GetLocalAddress(); + ASSERT_NE(serverAddress.SockAddr.Ipv4.sin_port, (uint16_t)0); + + ListenerContext.Reject = true; + + TcpClientContext ClientContext; + CxPlatSocket Client; Client.CreateTcp(Datapath, nullptr, &serverAddress.SockAddr, &ClientContext); + VERIFY_QUIC_SUCCESS(Client.GetInitStatus()); + ASSERT_NE(nullptr, Client.Socket); + ASSERT_NE(Client.GetLocalAddress().Ipv4.sin_port, (uint16_t)0); + + ASSERT_TRUE(CxPlatEventWaitWithTimeout(ClientContext.ConnectEvent, 500)); + ASSERT_TRUE(CxPlatEventWaitWithTimeout(ListenerContext.AcceptEvent, 500)); + ASSERT_EQ(true, ListenerContext.Rejected); + ASSERT_EQ(nullptr, ListenerContext.Server); + + ASSERT_TRUE(CxPlatEventWaitWithTimeout(ClientContext.DisconnectEvent, 500)); +} + TEST_P(DataPathTest, TcpDisconnect) { CxPlatDataPath Datapath(nullptr, &TcpRecvCallbacks); @@ -1134,7 +1205,7 @@ TEST_P(DataPathTest, TcpDataClient) ASSERT_NE(nullptr, SendBuffer); memcpy(SendBuffer->Buffer, ExpectedData, ExpectedDataSize); - VERIFY_QUIC_SUCCESS(Client.Send(SendData)); + Client.Send(SendData); ASSERT_TRUE(CxPlatEventWaitWithTimeout(ListenerContext.ServerContext.ReceiveEvent, 500)); } @@ -1179,11 +1250,7 @@ TEST_P(DataPathTest, TcpDataServer) ASSERT_NE(nullptr, SendBuffer); memcpy(SendBuffer->Buffer, ExpectedData, ExpectedDataSize); - VERIFY_QUIC_SUCCESS( - CxPlatSocketSend( - ListenerContext.Server, - &Route, - SendData)); + CxPlatSocketSend(ListenerContext.Server, &Route, SendData); ASSERT_TRUE(CxPlatEventWaitWithTimeout(ClientContext.ReceiveEvent, 500)); } diff --git a/src/platform/unittest/main.cpp b/src/platform/unittest/main.cpp index 6ecd5bd7d6..6ccdac1e7b 100644 --- a/src/platform/unittest/main.cpp +++ b/src/platform/unittest/main.cpp @@ -16,6 +16,7 @@ const char* PfxPath = nullptr; bool UseDuoNic = false; uint32_t Timeout = UINT32_MAX; const char* OsRunner = nullptr; +CXPLAT_WORKER_POOL WorkerPool; class QuicCoreTestEnvironment : public ::testing::Environment { public: @@ -23,9 +24,11 @@ class QuicCoreTestEnvironment : public ::testing::Environment { void SetUp() override { CxPlatSystemLoad(); ASSERT_TRUE(QUIC_SUCCEEDED(CxPlatInitialize())); + CxPlatWorkerPoolInit(&WorkerPool); watchdog = new CxPlatWatchdog(Timeout); } void TearDown() override { + CxPlatWorkerPoolUninit(&WorkerPool); CxPlatUninitialize(); CxPlatSystemUnload(); delete watchdog; diff --git a/src/plugins/trace/README.md b/src/plugins/trace/README.md index fa8c558f14..c97b4825eb 100644 --- a/src/plugins/trace/README.md +++ b/src/plugins/trace/README.md @@ -8,17 +8,21 @@ This page provides the install, setup and usage instructions for Windows Perform The following are currently only possible on Windows. Other platforms may be supported by WPA in the future. -The easiest way to use WPA is via the `./scripts/wpa.ps1` script, but additional detailed instructions can be found below. - ## Install WPA -1. Download the preview version from [the Windows Store](https://www.microsoft.com/store/productId/9N58QRW40DFW). -2. You should then be able to run WPA from: `$env:LOCALAPPDATA\Microsoft\WindowsApps\wpa.exe` +Download the preview version from [the Windows Store](https://www.microsoft.com/store/productId/9N58QRW40DFW) or (for MSFT internal) from http://aka.ms/getwpa. + +## Download MsQuic WPA Plugin + +1. Navigate to our [GitHub Action](https://github.com/microsoft/msquic/actions/workflows/plugins.yml?query=branch%3Amain) for building the plugin. +2. Click on the latest build. +3. Scroll to the bottom and download the `ptix_quictrace_Release` artifact. +4. Extract the `.ptix` file. -## Install MsQuic WPA Plugin +## Install the Plugin -1. Build the plugin via `QuicTrace.sln` or download it from the latest release (i.e. [v1.0.0](https://github.com/microsoft/msquic/releases/download/v1.0.0-129524/quic.wpa.zip)). -2. Update/create your WPA shortcut by adding `-addsearchdir `. +1. Open WPA and use the `Install Plugin` dialog to install the MsQuic WPA plugin. +2. Restart WPA. # Usage Instructions @@ -80,4 +84,4 @@ Change visualization type by drop down menu as shown in image below. Also you ca ![](images/quic_network.png) -**TODO** \ No newline at end of file +**TODO** diff --git a/src/plugins/trace/dll/DataModel/QuicEvents.cs b/src/plugins/trace/dll/DataModel/QuicEvents.cs index 4b8278df80..5dda14b161 100644 --- a/src/plugins/trace/dll/DataModel/QuicEvents.cs +++ b/src/plugins/trace/dll/DataModel/QuicEvents.cs @@ -32,7 +32,6 @@ public enum QuicApiType ConnectionStart, ConnectionSetConfiguration, ConnectionSendResumptionTicket, - ConnectionCompleteResumptionTicketValidation, StreamOpen, StreamClose, StreamStart, @@ -40,7 +39,9 @@ public enum QuicApiType StreamSend, StreamReceiveComplete, StreamReceiveSetEnabled, - StreamDatagramSend + StreamDatagramSend, + ConnectionCompleteResumptionTicketValidation, + ConnectionCompleteCertificateValidation } public enum QuicConnectionState diff --git a/src/plugins/trace/dll/Tables/QuicStreamLifetime.cs b/src/plugins/trace/dll/Tables/QuicStreamLifetime.cs index 469be65b69..557b60f681 100644 --- a/src/plugins/trace/dll/Tables/QuicStreamLifetime.cs +++ b/src/plugins/trace/dll/Tables/QuicStreamLifetime.cs @@ -84,6 +84,21 @@ public sealed class QuicStreamLifetimeTable new ColumnMetadata(new Guid("{D0612FB2-4243-4C13-9164-5D55837F7E04}"), "Type"), new UIHints { AggregationMode = AggregationMode.UniqueCount }); + private static readonly ColumnConfiguration processIdColumnConfig = + new ColumnConfiguration( + new ColumnMetadata(new Guid("{73bf47c1-a87e-473e-8337-dfc8442da9bb}"), "Process (ID)"), + new UIHints { AggregationMode = AggregationMode.Max }); + + private static readonly ColumnConfiguration threadIdColumnConfig = + new ColumnConfiguration( + new ColumnMetadata(new Guid("{b58d4999-21b8-4462-8dd7-6bf483d45b15}"), "ThreadId"), + new UIHints { AggregationMode = AggregationMode.Max }); + + private static readonly ColumnConfiguration cpuColumnConfig = + new ColumnConfiguration( + new ColumnMetadata(new Guid("{48ab57b9-e0df-4068-856a-a2c2ffdfa8f3}"), "CPU"), + new UIHints { AggregationMode = AggregationMode.Sum }); + private static readonly ColumnConfiguration countColumnConfig = new ColumnConfiguration( new ColumnMetadata(new Guid("{9583D245-BD70-4BA3-A249-088F0D6C0D8C}"), "Count"), @@ -102,6 +117,9 @@ public sealed class QuicStreamLifetimeTable typeColumnConfig, TableConfiguration.PivotColumn, TableConfiguration.LeftFreezeColumn, + processIdColumnConfig, + threadIdColumnConfig, + cpuColumnConfig, timeColumnConfig, TableConfiguration.RightFreezeColumn, TableConfiguration.GraphColumn, @@ -123,6 +141,9 @@ public static void BuildTable(ITableBuilder tableBuilder, QuicState quicState) var dataProjection = Projection.Index(events); table.AddColumn(typeColumnConfig, dataProjection.Compose(ProjectType)); + table.AddColumn(processIdColumnConfig, dataProjection.Compose(ProjectProcessId)); + table.AddColumn(threadIdColumnConfig, dataProjection.Compose(ProjectThreadId)); + table.AddColumn(cpuColumnConfig, dataProjection.Compose(ProjectCpu)); table.AddColumn(countColumnConfig, Projection.Constant(1)); table.AddColumn(timeColumnConfig, dataProjection.Compose(ProjectTime)); @@ -139,6 +160,21 @@ private static string ProjectType(QuicEvent evt) return evt.EventId == QuicEventId.StreamCreated ? "Stream Create" : "Stream Destroy"; } + private static uint ProjectProcessId(QuicEvent evt) + { + return evt.ProcessId; + } + + private static uint ProjectThreadId(QuicEvent evt) + { + return evt.ThreadId; + } + + private static ushort ProjectCpu(QuicEvent evt) + { + return evt.Processor; + } + private static Timestamp ProjectTime(QuicEvent evt) { return evt.TimeStamp; diff --git a/src/plugins/trace/dll/pluginManifest.json b/src/plugins/trace/dll/pluginManifest.json index e5844aac7a..1c6afb5973 100644 --- a/src/plugins/trace/dll/pluginManifest.json +++ b/src/plugins/trace/dll/pluginManifest.json @@ -2,7 +2,7 @@ "$schema": "https://raw.githubusercontent.com/microsoft/microsoft-performance-toolkit-sdk/main/src/PluginsSystem/Tools/Microsoft.Performance.Toolkit.Plugins.Cli/Manifest/PluginManifestSchema.json", "identity": { "id": "QuicTrace", - "version": "1.0.1" + "version": "1.0.3" }, "displayName": "QuicTrace", "description": "Used to open MsQuic trace files.", diff --git a/src/test/MsQuicTests.h b/src/test/MsQuicTests.h index 83943df6fa..f75e1a8aa7 100644 --- a/src/test/MsQuicTests.h +++ b/src/test/MsQuicTests.h @@ -21,6 +21,11 @@ extern QUIC_CREDENTIAL_CONFIG ServerSelfSignedCredConfig; extern QUIC_CREDENTIAL_CONFIG ServerSelfSignedCredConfigClientAuth; extern QUIC_CREDENTIAL_CONFIG ClientCertCredConfig; +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif +extern char CurrentWorkingDirectory[MAX_PATH + 1]; + #ifdef __cplusplus extern "C" { #endif @@ -46,6 +51,7 @@ void QuicTestConfigurationParam(); void QuicTestListenerParam(); void QuicTestConnectionParam(); void QuicTestTlsParam(); +void QuicTestTlsHandshakeInfo(_In_ bool EnableResumption); void QuicTestStreamParam(); void QuicTestGetPerfCounters(); void QuicTestVersionSettings(); @@ -706,6 +712,7 @@ static const GUID QUIC_TEST_DEVICE_INSTANCE = typedef struct { BOOLEAN UseDuoNic; + char CurrentDirectory[MAX_PATH]; } QUIC_TEST_CONFIGURATION_PARAMS; #define IOCTL_QUIC_TEST_CONFIGURATION \ @@ -1319,4 +1326,8 @@ typedef struct { #define IOCTL_QUIC_RUN_STREAM_MULTI_RECEIVE \ QUIC_CTL_CODE(124, METHOD_BUFFERED, FILE_WRITE_DATA) -#define QUIC_MAX_IOCTL_FUNC_CODE 124 +#define IOCTL_QUIC_RUN_VALIDATE_TLS_HANDSHAKE_INFO \ + QUIC_CTL_CODE(125, METHOD_BUFFERED, FILE_WRITE_DATA) + // BOOLEAN - EnableResumption + +#define QUIC_MAX_IOCTL_FUNC_CODE 125 diff --git a/src/test/bin/quic_gtest.cpp b/src/test/bin/quic_gtest.cpp index ffb97c9f50..c717d79bb2 100644 --- a/src/test/bin/quic_gtest.cpp +++ b/src/test/bin/quic_gtest.cpp @@ -21,6 +21,7 @@ bool TestingKernelMode = false; bool PrivateTestLibrary = false; bool UseDuoNic = false; +CXPLAT_WORKER_POOL WorkerPool; #if defined(QUIC_API_ENABLE_PREVIEW_FEATURES) bool UseQTIP = false; #endif @@ -44,6 +45,7 @@ class QuicTestEnvironment : public ::testing::Environment { void SetUp() override { CxPlatSystemLoad(); ASSERT_TRUE(QUIC_SUCCEEDED(CxPlatInitialize())); + CxPlatWorkerPoolInit(&WorkerPool); watchdog = new CxPlatWatchdog(Timeout); ASSERT_TRUE((SelfSignedCertParams = CxPlatGetSelfSignedCert( @@ -89,6 +91,12 @@ class QuicTestEnvironment : public ::testing::Environment { QUIC_TEST_CONFIGURATION_PARAMS Params { UseDuoNic, }; + +#ifdef _WIN32 + ASSERT_NE(GetCurrentDirectoryA(sizeof(Params.CurrentDirectory), Params.CurrentDirectory), 0); + strcat_s(Params.CurrentDirectory, "\\"); +#endif + ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_TEST_CONFIGURATION, Params)); } else { @@ -120,6 +128,12 @@ class QuicTestEnvironment : public ::testing::Environment { memcpy(&ClientCertCredConfig, ClientCertParams, sizeof(QUIC_CREDENTIAL_CONFIG)); ClientCertCredConfig.Flags |= QUIC_CREDENTIAL_FLAG_NO_CERTIFICATE_VALIDATION; QuicTestInitialize(); + +#ifdef _WIN32 + ASSERT_NE(GetCurrentDirectoryA(sizeof(CurrentWorkingDirectory), CurrentWorkingDirectory), 0); +#else + ASSERT_NE(getcwd(CurrentWorkingDirectory, sizeof(CurrentWorkingDirectory)), nullptr); +#endif } } void TearDown() override { @@ -133,6 +147,7 @@ class QuicTestEnvironment : public ::testing::Environment { CxPlatFreeSelfSignedCert(SelfSignedCertParams); CxPlatFreeSelfSignedCert(ClientCertParams); + CxPlatWorkerPoolUninit(&WorkerPool); CxPlatUninitialize(); CxPlatSystemUnload(); delete watchdog; @@ -283,6 +298,17 @@ TEST(ParameterValidation, ValidateTlsParam) { } } +TEST_P(WithBool, ValidateTlsHandshakeInfo) { + TestLoggerT Logger("QuicTestValidateTlsHandshakeInfo", GetParam()); + if (TestingKernelMode) { + if (IsWindows2022() || IsWindows2019()) GTEST_SKIP(); // Not supported on WS2019 or WS2022 + uint8_t EnableResumption = (uint8_t)GetParam(); + ASSERT_TRUE(DriverClient.Run(IOCTL_QUIC_RUN_VALIDATE_TLS_HANDSHAKE_INFO, EnableResumption)); + } else { + QuicTestTlsHandshakeInfo(GetParam()); + } +} + TEST(ParameterValidation, ValidateStreamParam) { TestLogger Logger("QuicTestValidateStreamParam"); if (TestingKernelMode) { diff --git a/src/test/bin/winkernel/control.cpp b/src/test/bin/winkernel/control.cpp index b4f9c7c50d..839457729c 100644 --- a/src/test/bin/winkernel/control.cpp +++ b/src/test/bin/winkernel/control.cpp @@ -523,6 +523,7 @@ size_t QUIC_IOCTL_BUFFER_SIZES[] = 0, 0, 0, + sizeof(BOOLEAN), }; CXPLAT_STATIC_ASSERT( @@ -563,6 +564,7 @@ typedef union { QUIC_RUN_FEATURE_NEGOTIATION FeatureNegotiationParams; QUIC_HANDSHAKE_LOSS_PARAMS HandshakeLossParams; BOOLEAN ClientShutdown; + BOOLEAN EnableResumption; } QUIC_IOCTL_PARAMS; #define QuicTestCtlRun(X) \ @@ -679,6 +681,15 @@ QuicTestCtlEvtIoDeviceControl( case IOCTL_QUIC_TEST_CONFIGURATION: CXPLAT_FRE_ASSERT(Params != nullptr); UseDuoNic = Params->TestConfigurationParams.UseDuoNic; + RtlCopyMemory(CurrentWorkingDirectory, "\\DosDevices\\", sizeof("\\DosDevices\\")); + Status = + RtlStringCbCatExA( + CurrentWorkingDirectory, + sizeof(CurrentWorkingDirectory), + Params->TestConfigurationParams.CurrentDirectory, + nullptr, + nullptr, + STRSAFE_NULL_ON_FAILURE); break; case IOCTL_QUIC_SET_CERT_PARAMS: @@ -1467,6 +1478,11 @@ QuicTestCtlEvtIoDeviceControl( QuicTestCtlRun(QuicTestConnectionPriority()); break; + case IOCTL_QUIC_RUN_VALIDATE_TLS_HANDSHAKE_INFO: + CXPLAT_FRE_ASSERT(Params != nullptr); + QuicTestCtlRun(QuicTestTlsHandshakeInfo(Params->EnableResumption != 0)); + break; + default: Status = STATUS_NOT_IMPLEMENTED; break; diff --git a/src/test/lib/ApiTest.cpp b/src/test/lib/ApiTest.cpp index af6ee42a00..4935cf1d65 100644 --- a/src/test/lib/ApiTest.cpp +++ b/src/test/lib/ApiTest.cpp @@ -2681,6 +2681,52 @@ void QuicTestGlobalParam() } } +#if DEBUG + // + // QUIC_PARAM_GLOBAL_PLATFORM_WORKER_POOL + // + { + TestScopeLogger LogScope0("QUIC_PARAM_GLOBAL_PLATFORM_WORKER_POOL"); + { + TestScopeLogger LogScope1("SetParam"); + // + // Invalid features + // + { + TestScopeLogger LogScope2("SetParam is not allowed"); + TEST_QUIC_STATUS( + QUIC_STATUS_INVALID_PARAMETER, + MsQuic->SetParam( + nullptr, + QUIC_PARAM_GLOBAL_PLATFORM_WORKER_POOL, + 0, + nullptr)); + } + } + + { + TestScopeLogger LogScope2("GetParam. Failed by missing MsQuicLib.WorkerPool"); + uint32_t Length = 0; + TEST_QUIC_STATUS( + QUIC_STATUS_BUFFER_TOO_SMALL, + MsQuic->GetParam( + nullptr, + QUIC_PARAM_GLOBAL_PLATFORM_WORKER_POOL, + &Length, + nullptr)); + TEST_EQUAL(Length, sizeof(CXPLAT_WORKER_POOL*)); + + CXPLAT_WORKER_POOL* WorkerPool = 0; + TEST_QUIC_SUCCEEDED( + MsQuic->GetParam( + nullptr, + QUIC_PARAM_GLOBAL_PLATFORM_WORKER_POOL, + &Length, + &WorkerPool)); + } + } +#endif + // // Invalid parameter // @@ -4533,6 +4579,13 @@ void QuicTestTlsParam() // { TestScopeLogger LogScope1("GetParam"); + TEST_QUIC_STATUS( + QUIC_STATUS_INVALID_PARAMETER, + Connection.GetParam( + QUIC_PARAM_TLS_HANDSHAKE_INFO, + nullptr, + nullptr)); + uint32_t Length = 0; TEST_QUIC_STATUS( QUIC_STATUS_BUFFER_TOO_SMALL, @@ -4717,6 +4770,141 @@ void QuicTestTlsParam() #endif } +struct TestTlsHandshakeInfoServerContext { + MsQuicConnection** Server; + MsQuicConfiguration* ServerConfiguration; + QUIC_STATUS GetParamStatus; +}; + +QUIC_STATUS +TestTlsHandshakeInfoListenerCallback( + _In_ MsQuicListener* /*Listener*/, + _In_opt_ void* ListenerContext, + _Inout_ QUIC_LISTENER_EVENT* Event) +{ + TestTlsHandshakeInfoServerContext* Context = (TestTlsHandshakeInfoServerContext*)ListenerContext; + if (Event->Type == QUIC_LISTENER_EVENT_NEW_CONNECTION) { + *Context->Server = new(std::nothrow) MsQuicConnection( + Event->NEW_CONNECTION.Connection, + CleanUpManual, + [](MsQuicConnection* Connection, void* Context, QUIC_CONNECTION_EVENT* Event) { + if (Event->Type == QUIC_CONNECTION_EVENT_CONNECTED) { + QUIC_HANDSHAKE_INFO Info = {}; + uint32_t Length = sizeof(Info); + ((TestTlsHandshakeInfoServerContext*)Context)->GetParamStatus = + MsQuic->GetParam( + *Connection, + QUIC_PARAM_TLS_HANDSHAKE_INFO, + &Length, + &Info); + } + return QUIC_STATUS_SUCCESS; + }, + Context); + (*Context->Server)->SetConfiguration(*Context->ServerConfiguration); + } + return QUIC_STATUS_SUCCESS; +} + +void +QuicTestTlsHandshakeInfo( + _In_ bool EnableResumption + ) +{ + MsQuicRegistration Registration; + TEST_TRUE(Registration.IsValid()); + + MsQuicAlpn Alpn("MsQuicTest"); + + MsQuicCredentialConfig ClientCredConfig; + MsQuicConfiguration ClientConfiguration(Registration, Alpn, ClientCertCredConfig); + TEST_TRUE(ClientConfiguration.IsValid()); + + MsQuicSettings Settings; + if (EnableResumption) { + Settings.SetServerResumptionLevel(QUIC_SERVER_RESUME_ONLY); + } + + MsQuicConfiguration ServerConfiguration(Registration, Alpn, Settings, ServerSelfSignedCredConfig); + TEST_TRUE(ServerConfiguration.IsValid()); + + TestTlsHandshakeInfoServerContext ServerContext = { nullptr, &ServerConfiguration, QUIC_STATUS_SUCCESS }; + + MsQuicListener Listener( + Registration, + CleanUpManual, + TestTlsHandshakeInfoListenerCallback, + &ServerContext); + TEST_QUIC_SUCCEEDED(Listener.GetInitStatus()); + + UniquePtr Server; + ServerContext.Server = (MsQuicConnection**)&Server; + Listener.Context = &ServerContext; + + QuicAddr ServerLocalAddr(QUIC_ADDRESS_FAMILY_INET); + TEST_QUIC_SUCCEEDED(Listener.Start(Alpn, ServerLocalAddr)); + TEST_QUIC_SUCCEEDED(Listener.GetLocalAddr(ServerLocalAddr)); + + MsQuicConnection Client(Registration); + TEST_QUIC_SUCCEEDED(Client.GetInitStatus()); + + if (UseDuoNic) { + QuicAddr RemoteAddr{QuicAddrGetFamily(ServerLocalAddr), ServerLocalAddr.GetPort()}; + QuicAddrSetToDuoNic(&RemoteAddr.SockAddr); + TEST_QUIC_SUCCEEDED(Client.SetRemoteAddr(RemoteAddr)); + } + + TEST_QUIC_SUCCEEDED( + Client.Start( + ClientConfiguration, + QUIC_ADDRESS_FAMILY_INET, + QUIC_LOCALHOST_FOR_AF(QUIC_ADDRESS_FAMILY_INET), + ServerLocalAddr.GetPort())); + + Client.HandshakeCompleteEvent.WaitForever(); + TEST_TRUE(Client.HandshakeComplete); + TEST_TRUE(Server); + Server->HandshakeCompleteEvent.WaitForever(); + TEST_TRUE(Server->HandshakeComplete); + + // + // Validate the GetParam succeeded in the CONNECTED callback. + // + TEST_QUIC_SUCCEEDED(ServerContext.GetParamStatus); + + QUIC_HANDSHAKE_INFO Info = {}; + uint32_t Length = sizeof(Info); + TEST_QUIC_SUCCEEDED( + Client.GetParam( + QUIC_PARAM_TLS_HANDSHAKE_INFO, + &Length, + &Info + )); + + if (EnableResumption) { + // + // The server should NOT have freed the TLS state, so this + // should succeed. + // + TEST_QUIC_SUCCEEDED( + Server->GetParam( + QUIC_PARAM_TLS_HANDSHAKE_INFO, + &Length, + &Info)); + } else { + // + // The server should have freed the TLS state by now, so this + // should fail. + // + TEST_EQUAL( + Server->GetParam( + QUIC_PARAM_TLS_HANDSHAKE_INFO, + &Length, + &Info), + QUIC_STATUS_INVALID_STATE); + } +} + void QuicTestStreamParam() { MsQuicRegistration Registration; diff --git a/src/test/lib/HandshakeTest.cpp b/src/test/lib/HandshakeTest.cpp index aec150c9e3..71cddd74c5 100644 --- a/src/test/lib/HandshakeTest.cpp +++ b/src/test/lib/HandshakeTest.cpp @@ -14,6 +14,8 @@ #include "HandshakeTest.cpp.clog.h" #endif +char CurrentWorkingDirectory[MAX_PATH + 1]; + QUIC_TEST_DATAPATH_HOOKS DatapathHooks::FuncTable = { DatapathHooks::CreateCallback, DatapathHooks::GetLocalAddressCallback, @@ -251,15 +253,14 @@ QuicTestConnect( ServerAcceptCtx.ExpectedCustomTicketValidationResult = QUIC_STATUS_INTERNAL_ERROR; } } - ServerAcceptCtx.TlsSecrets = &ServerSecrets; Listener.Context = &ServerAcceptCtx; { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); Client.SetHasRandomLoss(RandomLossPercentage != 0); - TEST_QUIC_SUCCEEDED(Client.SetTlsSecrets(&ClientSecrets)); if (ClientUsesOldVersion) { TEST_QUIC_SUCCEEDED( @@ -317,11 +318,15 @@ QuicTestConnect( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } TEST_TRUE(Server->GetIsConnected()); + ClientSecrets = Client.GetTlsSecrets(); + ServerSecrets = Server->GetTlsSecrets(); + TEST_EQUAL( ServerSecrets.IsSet.ClientRandom, ClientSecrets.IsSet.ClientRandom); @@ -861,6 +866,7 @@ QuicTestCustomServerCertificateValidation( TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); Client.SetExpectedCustomValidationResult(AcceptCert); Client.SetAsyncCustomValidationResult(AsyncValidation); if (!AcceptCert) { @@ -886,6 +892,7 @@ QuicTestCustomServerCertificateValidation( TEST_EQUAL(AcceptCert, Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -963,6 +970,7 @@ QuicTestCustomClientCertificateValidation( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); if (!AcceptCert) { Client.SetExpectedTransportCloseStatus(QUIC_STATUS_BAD_CERTIFICATE); @@ -1000,6 +1008,7 @@ QuicTestCustomClientCertificateValidation( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -1048,6 +1057,7 @@ QuicTestShutdownDuringHandshake( TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); Client.SetExpectedCustomValidationResult(TRUE); Client.SetAsyncCustomValidationResult(TRUE); Client.SetExpectedTransportCloseStatus(QUIC_STATUS_USER_CANCELED); @@ -1062,6 +1072,9 @@ QuicTestShutdownDuringHandshake( CxPlatSleep(1000); + TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); + // // By now, the handshake is waiting for custom certificate validation. // @@ -1256,6 +1269,7 @@ QuicTestVersionNegotiation( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -1270,6 +1284,9 @@ QuicTestVersionNegotiation( TEST_TRUE(Client.GetIsConnected()); TEST_TRUE(Client.GetStatistics().VersionNegotiation); TEST_EQUAL(Client.GetQuicVersion(), LATEST_SUPPORTED_VERSION); + + TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); } } } @@ -1353,6 +1370,7 @@ QuicTestVersionNegotiationRetry( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -1368,6 +1386,9 @@ QuicTestVersionNegotiationRetry( TEST_TRUE(Client.GetStatistics().VersionNegotiation); TEST_TRUE(Client.GetStatistics().StatelessRetry); TEST_EQUAL(Client.GetQuicVersion(), LATEST_SUPPORTED_VERSION); + + TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); } } } @@ -1444,6 +1465,7 @@ QuicTestCompatibleVersionNegotiation( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -1458,6 +1480,7 @@ QuicTestCompatibleVersionNegotiation( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -1550,6 +1573,7 @@ QuicTestCompatibleVersionNegotiationRetry( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -1564,6 +1588,7 @@ QuicTestCompatibleVersionNegotiationRetry( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -1640,6 +1665,7 @@ QuicTestCompatibleVersionNegotiationDefaultServer( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -1654,6 +1680,7 @@ QuicTestCompatibleVersionNegotiationDefaultServer( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -1737,6 +1764,7 @@ QuicTestCompatibleVersionNegotiationDefaultClient( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -1751,6 +1779,7 @@ QuicTestCompatibleVersionNegotiationDefaultClient( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -1827,6 +1856,7 @@ QuicTestIncompatibleVersionNegotiation( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -1841,6 +1871,7 @@ QuicTestIncompatibleVersionNegotiation( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -1930,6 +1961,7 @@ RunFailedVersionNegotiation( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); Client.SetExpectedTransportCloseStatus(ExpectedClientError); TEST_QUIC_SUCCEEDED( @@ -1944,6 +1976,7 @@ RunFailedVersionNegotiation( if (QUIC_FAILED(ExpectedServerError)) { TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); } else { TEST_EQUAL(nullptr, Server); } @@ -2169,6 +2202,7 @@ QuicTestConnectBadAlpn( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); Client.SetExpectedTransportCloseStatus(QUIC_STATUS_ALPN_NEG_FAILURE); TEST_QUIC_SUCCEEDED( @@ -2226,6 +2260,7 @@ QuicTestConnectBadSni( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); QuicAddr RemoteAddr(Family == 4 ? QUIC_ADDRESS_FAMILY_INET : QUIC_ADDRESS_FAMILY_INET6, true); if (UseDuoNic) { @@ -2744,6 +2779,7 @@ QuicTestConnectClientCertificate( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); if (!UseClientCertificate) { Client.SetExpectedTransportCloseStatus(QUIC_STATUS_REQUIRED_CERTIFICATE); } @@ -2761,6 +2797,7 @@ QuicTestConnectClientCertificate( } TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (UseClientCertificate) { if (!Server->WaitForConnectionComplete()) { return; @@ -2844,6 +2881,7 @@ QuicTestValidAlpnLengths( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -2859,6 +2897,7 @@ QuicTestValidAlpnLengths( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -2909,6 +2948,7 @@ QuicTestConnectExpiredServerCertificate( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); Client.SetExpectedTransportCloseStatus(QUIC_STATUS_EXPIRED_CERTIFICATE); TEST_QUIC_SUCCEEDED( @@ -2925,6 +2965,7 @@ QuicTestConnectExpiredServerCertificate( TEST_EQUAL(false, Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -2973,6 +3014,7 @@ QuicTestConnectValidServerCertificate( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -2988,6 +3030,7 @@ QuicTestConnectValidServerCertificate( TEST_EQUAL(true, Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -3036,6 +3079,7 @@ QuicTestConnectValidClientCertificate( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -3051,6 +3095,7 @@ QuicTestConnectValidClientCertificate( TEST_EQUAL(true, Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -3099,6 +3144,7 @@ QuicTestConnectExpiredClientCertificate( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -3118,6 +3164,7 @@ QuicTestConnectExpiredClientCertificate( TEST_EQUAL(true, Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -3480,6 +3527,7 @@ QuicTestResumptionAcrossVersions() { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); VersionSettings.SetAllVersionLists(SecondClientVersions, ARRAYSIZE(SecondClientVersions)); TEST_QUIC_SUCCEEDED(ClientConfiguration.SetVersionSettings(VersionSettings)); @@ -3506,6 +3554,7 @@ QuicTestResumptionAcrossVersions() TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -3601,6 +3650,7 @@ QuicTestChangeAlpn( { TestConnection Client(Registration); TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); TEST_QUIC_SUCCEEDED( Client.Start( @@ -3616,6 +3666,7 @@ QuicTestChangeAlpn( TEST_TRUE(Client.GetIsConnected()); TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } @@ -3791,6 +3842,7 @@ QuicTestCustomVNTP( &Disable)); } TEST_TRUE(Client.IsValid()); + Client.SetSslKeyLogFilePath(); Client.SetExpectedTransportCloseStatus(QUIC_STATUS_INTERNAL_ERROR); TEST_QUIC_SUCCEEDED( @@ -3807,6 +3859,7 @@ QuicTestCustomVNTP( if (TestServer) { TEST_NOT_EQUAL(nullptr, Server); + Server->SetSslKeyLogFilePath(); if (!Server->WaitForConnectionComplete()) { return; } diff --git a/src/test/lib/QuicDrill.cpp b/src/test/lib/QuicDrill.cpp index fea062a0b9..407f0f2caf 100644 --- a/src/test/lib/QuicDrill.cpp +++ b/src/test/lib/QuicDrill.cpp @@ -24,6 +24,12 @@ extern "C" { #include "quic_datapath.h" } +#ifndef _KERNEL_MODE +extern CXPLAT_WORKER_POOL WorkerPool; +#else +static CXPLAT_WORKER_POOL WorkerPool; +#endif + void QuicDrillTestVarIntEncoder( ) @@ -140,6 +146,7 @@ struct DrillSender { 0, &DatapathCallbacks, NULL, + &WorkerPool, NULL, &Datapath); if (QUIC_FAILED(Status)) { @@ -191,7 +198,6 @@ struct DrillSender { _In_ const DrillBuffer& PacketBuffer ) { - QUIC_STATUS Status = QUIC_STATUS_SUCCESS; CXPLAT_FRE_ASSERT(PacketBuffer.size() <= UINT16_MAX); const uint16_t DatagramLength = (uint16_t) PacketBuffer.size(); @@ -208,8 +214,7 @@ struct DrillSender { if (SendBuffer == nullptr) { TEST_FAILURE("Buffer null"); - Status = QUIC_STATUS_OUT_OF_MEMORY; - return Status; + return QUIC_STATUS_OUT_OF_MEMORY; } // @@ -217,13 +222,12 @@ struct DrillSender { // memcpy(SendBuffer->Buffer, PacketBuffer.data(), DatagramLength); - Status = - CxPlatSocketSend( - Binding, - &Route, - SendData); + CxPlatSocketSend( + Binding, + &Route, + SendData); - return Status; + return QUIC_STATUS_SUCCESS; } }; diff --git a/src/test/lib/TestConnection.cpp b/src/test/lib/TestConnection.cpp index 058c01dbb7..60476d463e 100644 --- a/src/test/lib/TestConnection.cpp +++ b/src/test/lib/TestConnection.cpp @@ -30,7 +30,7 @@ TestConnection::TestConnection( NewStreamCallback(NewStreamCallbackHandler), ShutdownCompleteCallback(nullptr), DatagramsSent(0), DatagramsCanceled(0), DatagramsSuspectLost(0), DatagramsLost(0), DatagramsAcknowledged(0), NegotiatedAlpn(nullptr), - NegotiatedAlpnLength(0), Context(nullptr) + NegotiatedAlpnLength(0), SslKeyLogFileName(nullptr), Context(nullptr) { CxPlatEventInitialize(&EventConnectionComplete, TRUE, FALSE); CxPlatEventInitialize(&EventPeerClosed, TRUE, FALSE); @@ -42,6 +42,10 @@ TestConnection::TestConnection( } else { MsQuic->SetCallbackHandler(QuicConnection, (void*)QuicConnectionHandler, this); } + QUIC_STATUS Status = SetTlsSecrets(&TlsSecrets); + if (QUIC_FAILED(Status)) { + TEST_FAILURE("SetTlsSecrets failed, 0x%x", Status); + } } TestConnection::TestConnection( @@ -60,7 +64,7 @@ TestConnection::TestConnection( NewStreamCallback(NewStreamCallbackHandler), ShutdownCompleteCallback(nullptr), DatagramsSent(0), DatagramsCanceled(0), DatagramsSuspectLost(0), DatagramsLost(0), DatagramsAcknowledged(0), NegotiatedAlpn(nullptr), - NegotiatedAlpnLength(0), Context(nullptr) + NegotiatedAlpnLength(0), SslKeyLogFileName(nullptr), Context(nullptr) { CxPlatEventInitialize(&EventConnectionComplete, TRUE, FALSE); CxPlatEventInitialize(&EventPeerClosed, TRUE, FALSE); @@ -77,6 +81,10 @@ TestConnection::TestConnection( TEST_FAILURE("MsQuic->ConnectionOpen failed, 0x%x.", Status); QuicConnection = nullptr; } + Status = SetTlsSecrets(&TlsSecrets); + if (QUIC_FAILED(Status)) { + TEST_FAILURE("SetTlsSecrets failed, 0x%x", Status); + } } TestConnection::~TestConnection() @@ -92,6 +100,35 @@ TestConnection::~TestConnection() if (EventDeleted) { CxPlatEventSet(*EventDeleted); } + if (SslKeyLogFileName != nullptr) { +#ifdef _KERNEL_MODE + char SslKeyLogFileFullPathName[MAX_PATH + 1]; + NTSTATUS Status = + RtlStringCbCopyA( + SslKeyLogFileFullPathName, + sizeof(SslKeyLogFileFullPathName), + CurrentWorkingDirectory); + if (!NT_SUCCESS(Status)) { + TEST_FAILURE("RtlStringCbCopyA failed"); + return; + } + Status = + RtlStringCbCatExA( + SslKeyLogFileFullPathName, + sizeof(SslKeyLogFileFullPathName), + SslKeyLogFileName, + nullptr, + nullptr, + STRSAFE_NULL_ON_FAILURE); + if (!NT_SUCCESS(Status)) { + TEST_FAILURE("RtlStringCbCatExA failed"); + return; + } + WriteSslKeyLogFile(SslKeyLogFileFullPathName, TlsSecrets); +#else + WriteSslKeyLogFile(SslKeyLogFileName, TlsSecrets); +#endif + } } QUIC_STATUS diff --git a/src/test/lib/TestConnection.h b/src/test/lib/TestConnection.h index 1beeb9c3d3..8338aee758 100644 --- a/src/test/lib/TestConnection.h +++ b/src/test/lib/TestConnection.h @@ -17,6 +17,8 @@ enum NEW_STREAM_START_TYPE { NEW_STREAM_START_ASYNC // Start asynchronously }; +#define DEFAULT_SSLKEYLOGFILE_NAME "sslkeylogfile.txt" + // // Callback for processing peer created streams. // @@ -96,6 +98,9 @@ class TestConnection const uint8_t* NegotiatedAlpn; uint8_t NegotiatedAlpnLength; + QUIC_TLS_SECRETS TlsSecrets; + const char* SslKeyLogFileName; + QUIC_STATUS HandleConnectionEvent( _Inout_ QUIC_CONNECTION_EVENT* Event @@ -309,4 +314,8 @@ class TestConnection uint8_t GetNegotiatedAlpnLength() const; QUIC_STATUS SetTlsSecrets(QUIC_TLS_SECRETS* Secrets); + + QUIC_TLS_SECRETS GetTlsSecrets() const { return TlsSecrets; } + + void SetSslKeyLogFilePath(const char* Path = DEFAULT_SSLKEYLOGFILE_NAME) { SslKeyLogFileName = Path; } }; diff --git a/src/test/lib/precomp.h b/src/test/lib/precomp.h index b0590e8853..fe3a649316 100644 --- a/src/test/lib/precomp.h +++ b/src/test/lib/precomp.h @@ -24,6 +24,7 @@ #include "msquicp.h" #include "quic_versions.h" #include "quic_trace.h" +#include "msquichelper.h" #include "quic_var_int.h" #include "../core/quicdef.h" diff --git a/src/tools/attack/attack.cpp b/src/tools/attack/attack.cpp index 38b0fad499..92428cec6f 100644 --- a/src/tools/attack/attack.cpp +++ b/src/tools/attack/attack.cpp @@ -31,6 +31,7 @@ const QUIC_HKDF_LABELS HkdfLabels = { "quic key", "quic iv", "quic hp", "quic ku" }; static CXPLAT_DATAPATH* Datapath; +static CXPLAT_WORKER_POOL WorkerPool; static PacketWriter* Writer; static uint32_t AttackType; @@ -463,10 +464,12 @@ main( }; CxPlatSystemLoad(); CxPlatInitialize(); + CxPlatWorkerPoolInit(&WorkerPool); CxPlatDataPathInitialize( 0, &DatapathCallbacks, NULL, + NULL, &DatapathFlags, &Datapath); @@ -510,6 +513,7 @@ main( Error: CxPlatDataPathUninitialize(Datapath); + CxPlatWorkerPoolUninit(&WorkerPool); CxPlatUninitialize(); CxPlatSystemUnload(); } diff --git a/src/tools/lb/loadbalancer.cpp b/src/tools/lb/loadbalancer.cpp index 5a8817313e..e87ec0cc20 100644 --- a/src/tools/lb/loadbalancer.cpp +++ b/src/tools/lb/loadbalancer.cpp @@ -20,6 +20,7 @@ bool Verbose = false; CXPLAT_DATAPATH* Datapath; +CXPLAT_WORKER_POOL WorkerPool; struct LbInterface* PublicInterface; std::vector PrivateAddrs; @@ -212,9 +213,10 @@ main(int argc, char **argv) CxPlatSystemLoad(); CxPlatInitialize(); + CxPlatWorkerPoolInit(&WorkerPool); CXPLAT_UDP_DATAPATH_CALLBACKS LbUdpCallbacks { LbReceive, NoOpUnreachable }; - CxPlatDataPathInitialize(0, &LbUdpCallbacks, nullptr, nullptr, &Datapath); + CxPlatDataPathInitialize(0, &LbUdpCallbacks, nullptr, &WorkerPool, nullptr, &Datapath); PublicInterface = new LbPublicInterface(&PublicAddr); printf("Press Enter to exit.\n\n"); @@ -222,6 +224,7 @@ main(int argc, char **argv) delete PublicInterface; CxPlatDataPathUninitialize(Datapath); + CxPlatWorkerPoolUninit(&WorkerPool); CxPlatUninitialize(); CxPlatSystemUnload(); diff --git a/src/tools/load/load.cpp b/src/tools/load/load.cpp index 1e7f9010fd..4a53276484 100644 --- a/src/tools/load/load.cpp +++ b/src/tools/load/load.cpp @@ -10,20 +10,23 @@ #include "msquic.hpp" const MsQuicApi* MsQuic; +CXPLAT_WORKER_POOL WorkerPool; volatile long ConnectedCount; volatile long ConnectionsActive; void ResolveServerAddress(const char* ServerName, QUIC_ADDR& ServerAddress) { CxPlatSystemLoad(); CxPlatInitialize(); + CxPlatWorkerPoolInit(&WorkerPool); CXPLAT_DATAPATH* Datapath = nullptr; //QuicAddrSetFamily(&ServerAddress, AF_INET); - if (QUIC_FAILED(CxPlatDataPathInitialize(0,nullptr,nullptr,nullptr,&Datapath)) || + if (QUIC_FAILED(CxPlatDataPathInitialize(0,nullptr,nullptr,&WorkerPool,nullptr,&Datapath)) || QUIC_FAILED(CxPlatDataPathResolveAddress(Datapath,ServerName,&ServerAddress))) { printf("Failed to resolve IP address!\n"); exit(1); } CxPlatDataPathUninitialize(Datapath); + CxPlatWorkerPoolUninit(&WorkerPool); CxPlatUninitialize(); CxPlatSystemUnload(); } diff --git a/src/tools/pcp/pcp.cpp b/src/tools/pcp/pcp.cpp index 3160e73f79..5a4926a8cb 100644 --- a/src/tools/pcp/pcp.cpp +++ b/src/tools/pcp/pcp.cpp @@ -44,6 +44,8 @@ PcpCallback( } } +static CXPLAT_WORKER_POOL WorkerPool; + int QUIC_MAIN_EXPORT main( @@ -61,8 +63,9 @@ main( CxPlatSystemLoad(); CxPlatInitialize(); + CxPlatWorkerPoolInit(&WorkerPool); CxPlatRandom(sizeof(PcpNonce), PcpNonce); - CxPlatDataPathInitialize(0, nullptr, nullptr, nullptr, &Datapath); + CxPlatDataPathInitialize(0, nullptr, nullptr, &WorkerPool, nullptr, &Datapath); QUIC_STATUS Status = CxPlatPcpInitialize( @@ -97,6 +100,7 @@ main( CxPlatPcpUninitialize(PcpContext); } CxPlatDataPathUninitialize(Datapath); + CxPlatWorkerPoolUninit(&WorkerPool); CxPlatUninitialize(); CxPlatSystemUnload(); diff --git a/src/tools/recvfuzz/recvfuzz.cpp b/src/tools/recvfuzz/recvfuzz.cpp index b31ab3179a..178fb00e97 100644 --- a/src/tools/recvfuzz/recvfuzz.cpp +++ b/src/tools/recvfuzz/recvfuzz.cpp @@ -3,7 +3,7 @@ Copyright (c) Microsoft Corporation. Licensed under the MIT License. -Abstract: +Abstract: Packet Fuzzer tool in the receive path. --*/ @@ -26,6 +26,7 @@ #include "msquic.hpp" const MsQuicApi* MsQuic; +CXPLAT_WORKER_POOL WorkerPool; uint64_t MagicCid = 0x989898989898989ull; const QUIC_HKDF_LABELS HkdfLabels = { "quic key", "quic iv", "quic hp", "quic ku" }; uint64_t RunTimeMs = 60000; @@ -124,7 +125,7 @@ T GetRandom(T UpperBound) { _IRQL_requires_max_(DISPATCH_LEVEL) _Function_class_(CXPLAT_DATAPATH_RECEIVE_CALLBACK) void -UdpRecvCallback( +UdpRecvCallback( _In_ CXPLAT_SOCKET* Binding, _In_ void* Context, _In_ CXPLAT_RECV_DATA* RecvBufferChain @@ -171,11 +172,11 @@ UdpRecvCallback( Packet.KeyType = QuicPacketTypeToKeyTypeV1(Packet.LH->Type); } Packet.Encrypted = TRUE; - if (Packet.AvailBufferLength >= Packet.HeaderLength && - (memcmp(Packet.DestCid, &CurrSrcCid, sizeof(uint64_t)) == 0) && + if (Packet.AvailBufferLength >= Packet.HeaderLength && + (memcmp(Packet.DestCid, &CurrSrcCid, sizeof(uint64_t)) == 0) && (Packet.LH->Type == QUIC_INITIAL_V1 || Packet.LH->Type == QUIC_HANDSHAKE_V1)) { Packet.AvailBufferLength = Packet.HeaderLength + Packet.PayloadLength; - QUIC_RX_PACKET* PacketCopy = (QUIC_RX_PACKET *)CXPLAT_ALLOC_NONPAGED(sizeof(QUIC_RX_PACKET) + Packet.AvailBufferLength + Packet.DestCidLen + Packet.SourceCidLen, QUIC_POOL_TOOL); + QUIC_RX_PACKET* PacketCopy = (QUIC_RX_PACKET *)CXPLAT_ALLOC_NONPAGED(sizeof(QUIC_RX_PACKET) + Packet.AvailBufferLength + Packet.DestCidLen + Packet.SourceCidLen, QUIC_POOL_TOOL); memcpy(PacketCopy, &Packet, sizeof(QUIC_RX_PACKET)); PacketCopy->AvailBuffer = (uint8_t*)(PacketCopy + 1); memcpy((void *)PacketCopy->AvailBuffer, Packet.AvailBuffer, Packet.AvailBufferLength); @@ -184,7 +185,7 @@ UdpRecvCallback( PacketCopy->SourceCid = PacketCopy->DestCid + Packet.DestCidLen; memcpy((void *)PacketCopy->SourceCid, Packet.SourceCid, Packet.SourceCidLen); PacketQueue.push_back(PacketCopy); - } + } Packet.AvailBuffer += Packet.AvailBufferLength; } while (Packet.AvailBuffer - Datagram->Buffer < Datagram->BufferLength); Datagram = Datagram->Next; @@ -219,7 +220,7 @@ struct TlsContext State.Buffer = (uint8_t*)CXPLAT_ALLOC_NONPAGED(8000, QUIC_POOL_TOOL); State.BufferAllocLength = 8000; } - void CreateContext(uint64_t initSrcCid = MagicCid) { + void CreateContext(uint64_t initSrcCid = MagicCid) { uint8_t *stateBuffer = State.Buffer; CxPlatZeroMemory(&State, sizeof(State)); State.Buffer = stateBuffer; @@ -233,7 +234,7 @@ struct TlsContext OnRecvQuicTP, NULL }; - + if (QUIC_FAILED( CxPlatTlsSecConfigCreate( &CredConfig, @@ -417,7 +418,7 @@ bool WriteAckFrame( _Inout_ uint16_t* Offset, _In_ uint16_t BufferLength, _Out_writes_to_(BufferLength, *Offset) uint8_t* Buffer - ) + ) { QUIC_RANGE AckRange; QuicRangeInitialize(QUIC_MAX_RANGE_DECODE_ACKS, &AckRange); @@ -425,11 +426,11 @@ bool WriteAckFrame( QuicRangeAddRange(&AckRange, LargestAcknowledge, 1, &RangeUpdated); uint64_t AckDelay = 40; if (!QuicAckFrameEncode( - &AckRange, - AckDelay, - nullptr, - Offset, - BufferLength, + &AckRange, + AckDelay, + nullptr, + Offset, + BufferLength, Buffer)) { printf("QuicAckFrameEncode failure!\n"); return false; @@ -437,11 +438,11 @@ bool WriteAckFrame( return true; } -bool WriteCryptoFrame( +bool WriteCryptoFrame( _Inout_ uint16_t* Offset, _In_ uint16_t BufferLength, _Out_writes_to_(BufferLength, *Offset) - uint8_t* Buffer, + uint8_t* Buffer, _In_ TlsContext* ClientContext, _In_ PacketParams* PacketParams ) @@ -491,7 +492,7 @@ bool WriteCryptoFrame( return true; } -bool WriteClientPacket( +bool WriteClientPacket( _In_ uint32_t PacketNumber, _In_ uint16_t BufferLength, _Out_writes_to_(BufferLength, *PacketLength) @@ -509,9 +510,9 @@ bool WriteClientPacket( for (int i = 0; i < PacketParams->NumFrames; i++) { if (PacketParams->FrameTypes[i] == QUIC_FRAME_ACK) { if (!WriteAckFrame( - PacketParams->LargestAcknowledge, - &FrameBufferLength, - BufferSize, + PacketParams->LargestAcknowledge, + &FrameBufferLength, + BufferSize, FrameBuffer)) { return false; } @@ -519,10 +520,10 @@ bool WriteClientPacket( if (PacketParams->FrameTypes[i] == QUIC_FRAME_CRYPTO) { if (!WriteCryptoFrame( - &FrameBufferLength, - BufferSize, - FrameBuffer, - ClientContext, + &FrameBufferLength, + BufferSize, + FrameBuffer, + ClientContext, PacketParams)) { return false; } @@ -533,7 +534,7 @@ bool WriteClientPacket( QUIC_CID* DestCid = (QUIC_CID*)DestCidBuffer; QUIC_CID* SourceCid = (QUIC_CID*)SourceCidBuffer; - + DestCid->IsInitial = TRUE; DestCid->Length = PacketParams->DestCidLen; @@ -577,19 +578,19 @@ bool WriteClientPacket( void fuzzPacket(uint8_t* Packet, uint16_t PacketLength) { uint8_t numIteration = (uint8_t)GetRandom(256); for(int i = 0; i < numIteration; i++){ - Packet[GetRandom(PacketLength)] = (uint8_t)GetRandom(256); + Packet[GetRandom(PacketLength)] = (uint8_t)GetRandom(256); } } void sendPacket( - CXPLAT_SOCKET* Binding, - CXPLAT_ROUTE Route, - int64_t* PacketCount, - int64_t* TotalByteCount, - PacketParams* PacketParams, - bool fuzzing = true, + CXPLAT_SOCKET* Binding, + CXPLAT_ROUTE Route, + int64_t* PacketCount, + int64_t* TotalByteCount, + PacketParams* PacketParams, + bool fuzzing = true, TlsContext* ClientContext = nullptr) { - const uint16_t DatagramLength = QUIC_MIN_INITIAL_LENGTH; + const uint16_t DatagramLength = QUIC_MIN_INITIAL_LENGTH; CXPLAT_SEND_CONFIG SendConfig = { &Route, DatagramLength, CXPLAT_ECN_NON_ECT, 0 }; CXPLAT_SEND_DATA* SendData = CxPlatSendDataAlloc(Binding, &SendConfig); if (!SendData) { @@ -612,7 +613,7 @@ void sendPacket( CxPlatSendDataFree(SendData); return; } - + uint16_t PacketNumberOffset = HeaderLength - sizeof(uint32_t); uint8_t* DestCid = (uint8_t*)(Packet + sizeof(QUIC_LONG_HEADER_V1)); @@ -622,9 +623,9 @@ void sendPacket( } else { memcpy(DestCid, PacketParams->DestCid, PacketParams->DestCidLen); } - + memcpy(SrcCid, PacketParams->SourceCid, PacketParams->SourceCidLen); - + if (fuzzing) { fuzzPacket(Packet, sizeof(Packet)); } @@ -703,15 +704,8 @@ void sendPacket( break; } } - - if (QUIC_FAILED( - CxPlatSocketSend( - Binding, - &Route, - SendData))) { - printf("Send failed!\n"); - exit(0); - } + + CxPlatSocketSend(Binding, &Route, SendData); } void fuzz(CXPLAT_SOCKET* Binding, CXPLAT_ROUTE Route) { @@ -765,11 +759,11 @@ void fuzz(CXPLAT_SOCKET* Binding, CXPLAT_ROUTE Route) { while (!PacketQueue.empty()) { QUIC_RX_PACKET* packet = PacketQueue.front(); - if (!packet->DestCidLen || - !packet->DestCid || packet->PayloadLength < 4 + CXPLAT_HP_SAMPLE_LENGTH || + if (!packet->DestCidLen || + !packet->DestCid || packet->PayloadLength < 4 + CXPLAT_HP_SAMPLE_LENGTH || (memcmp(packet->DestCid, &CurrSrcCid, sizeof(uint64_t)) != 0)) { CXPLAT_FREE(packet, QUIC_POOL_TOOL); - PacketQueue.pop_front(); + PacketQueue.pop_front(); continue; } if (packet->LH->Type == QUIC_INITIAL_V1) { @@ -782,11 +776,11 @@ void fuzz(CXPLAT_SOCKET* Binding, CXPLAT_ROUTE Route) { packet->AvailBuffer + packet->HeaderLength + 4, CXPLAT_HP_SAMPLE_LENGTH); // same step for all long header packets - - QUIC_PACKET_KEY_TYPE KeyType = packet->KeyType; + + QUIC_PACKET_KEY_TYPE KeyType = packet->KeyType; if (HandshakeClientContext.State.ReadKeys[KeyType] == nullptr) { CXPLAT_FREE(packet, QUIC_POOL_TOOL); - PacketQueue.pop_front(); + PacketQueue.pop_front(); continue; } if (QUIC_FAILED( @@ -798,7 +792,7 @@ void fuzz(CXPLAT_SOCKET* Binding, CXPLAT_ROUTE Route) { printf("Failed to Compute Mask\n"); } uint8_t CompressedPacketNumberLength = 0; - ((uint8_t*)packet->AvailBuffer)[0] ^= HpMask[0] & 0x0F; + ((uint8_t*)packet->AvailBuffer)[0] ^= HpMask[0] & 0x0F; CompressedPacketNumberLength = packet->LH->PnLength + 1; for (uint8_t i = 0; i < CompressedPacketNumberLength; i++) { ((uint8_t*)packet->AvailBuffer)[packet->HeaderLength + i] ^= HpMask[1 + i]; @@ -834,11 +828,11 @@ void fuzz(CXPLAT_SOCKET* Binding, CXPLAT_ROUTE Route) { (uint8_t*)Payload))) { // Buffer printf("CxPlatDecrypt failed\n"); CXPLAT_FREE(packet, QUIC_POOL_TOOL); - PacketQueue.pop_front(); + PacketQueue.pop_front(); continue; } packet->PayloadLength -= CXPLAT_ENCRYPTION_OVERHEAD; - + QUIC_VAR_INT FrameType INIT_NO_SAL(0); uint16_t offset = 0; uint16_t PayloadLength = packet->PayloadLength; @@ -904,12 +898,12 @@ void fuzz(CXPLAT_SOCKET* Binding, CXPLAT_ROUTE Route) { sendPacket(Binding, Route, &HandshakePacketCount, &TotalByteCount, &HandshakePacketParams, true, &HandshakeClientContext); handshakeComplete = FALSE; CXPLAT_FREE(packet, QUIC_POOL_TOOL); - PacketQueue.pop_front(); + PacketQueue.pop_front(); break; } CXPLAT_FREE(packet, QUIC_POOL_TOOL); - PacketQueue.pop_front(); - } + PacketQueue.pop_front(); + } for (uint8_t i = 0; i < QUIC_PACKET_KEY_COUNT; ++i) { if (HandshakeClientContext.State.ReadKeys[i] != nullptr) { @@ -920,12 +914,12 @@ void fuzz(CXPLAT_SOCKET* Binding, CXPLAT_ROUTE Route) { QuicPacketKeyFree(HandshakeClientContext.State.WriteKeys[i]); HandshakeClientContext.State.WriteKeys[i] = nullptr; } - } + } } } while (!PacketQueue.empty()) { QUIC_RX_PACKET* packet = PacketQueue.front(); - CXPLAT_FREE(packet, QUIC_POOL_TOOL); + CXPLAT_FREE(packet, QUIC_POOL_TOOL); PacketQueue.pop_front(); } printf("Total Initial Packets sent: %lld\n", (long long)InitialPacketCount); @@ -940,10 +934,12 @@ void start() { UdpUnreachCallback, }; MsQuic = new MsQuicApi(); + CxPlatWorkerPoolInit(&WorkerPool); QUIC_STATUS Status = CxPlatDataPathInitialize( 0, &DatapathCallbacks, NULL, + &WorkerPool, NULL, &Datapath); if (QUIC_FAILED(Status)) { @@ -1018,7 +1014,7 @@ main(int argc, char **argv) { uint32_t RngSeed = 0; if (!TryGetValue(argc, argv, "seed", &RngSeed)) { CxPlatRandom(sizeof(RngSeed), &RngSeed); - } + } printf("Using seed value: %u\n", RngSeed); srand(RngSeed); start(); diff --git a/submodules/googletest b/submodules/googletest index ff233bdd4c..0953a17a42 160000 --- a/submodules/googletest +++ b/submodules/googletest @@ -1 +1 @@ -Subproject commit ff233bdd4cac0a0bf6e5cd45bda3406814cb2796 +Subproject commit 0953a17a4281fc26831da647ad3fcd5e21e6473b