From c3119b6e8d392dc340de392d7e7204391ddbc916 Mon Sep 17 00:00:00 2001 From: Alfredo Moralejo Date: Apr 24 2024 10:44:48 +0000 Subject: Import ovn23.09-23.09.3-5.el9fdp.src.rpm from FDP --- diff --git a/.ovn.metadata b/.ovn.metadata index 906eb34..e0ddafb 100644 --- a/.ovn.metadata +++ b/.ovn.metadata @@ -1,5 +1,5 @@ 002450621b33c5690060345b0aac25bc2426d675 SOURCES/docutils-0.12.tar.gz 8746fd38571d535d663102d7023d40ae5f9f2329 SOURCES/openvswitch-49e64f1.tar.gz -1ad2a2bdb68e5e984310a8519d190350001f433a SOURCES/ovn-23.09.0.tar.gz +79fcdaccaa2229148d2f5c299d5e1ba51ea27ac0 SOURCES/ovn-23.09.3.tar.gz d34f96421a86004aa5d26ecf975edefd09f948b1 SOURCES/Pygments-1.4.tar.gz 6beb30f18ffac3de7689b7fd63e9a8a7d9c8df3a SOURCES/Sphinx-1.1.3.tar.gz diff --git a/SOURCES/ovn23.09.patch b/SOURCES/ovn23.09.patch index f439450..cefc342 100644 --- a/SOURCES/ovn23.09.patch +++ b/SOURCES/ovn23.09.patch @@ -1,13407 +1,57 @@ -diff --git a/.ci/ci.sh b/.ci/ci.sh -index 10f11939c..3f1b41ead 100755 ---- a/.ci/ci.sh -+++ b/.ci/ci.sh -@@ -23,7 +23,7 @@ CONTAINER_WORKDIR="/workspace/ovn-tmp" - IMAGE_NAME=${IMAGE_NAME:-"ovn-org/ovn-tests"} - - # Test variables --ARCH=${ARCH:-$(uname -i)} -+ARCH=${ARCH:-$(uname -m)} - CC=${CC:-gcc} - - -@@ -105,6 +105,16 @@ function run_tests() { - " - } - -+function check_clang_version_ge() { -+ lower=$1 -+ version=$(clang --version | head -n1 | cut -d' ' -f3) -+ if ! echo -e "$lower\n$version" | sort -CV; then -+ return 1 -+ fi -+ -+ return 0 -+} -+ - options=$(getopt --options "" \ - --long help,shell,archive-logs,jobs:,ovn-path:,ovs-path:,image-name:\ - -- "${@}") -@@ -149,7 +159,7 @@ while true; do - done - - # Workaround for https://bugzilla.redhat.com/2153359 --if [ "$ARCH" = "aarch64" ]; then -+if [ "$ARCH" = "aarch64" ] && ! check_clang_version_ge "16.0.0"; then - ASAN_OPTIONS="detect_leaks=0" - fi - -diff --git a/.ci/linux-build.sh b/.ci/linux-build.sh -index 5a79a52da..7270b9e60 100755 ---- a/.ci/linux-build.sh -+++ b/.ci/linux-build.sh -@@ -80,7 +80,7 @@ function configure_gcc() - # We should install gcc-multilib for x86 build, we cannot - # do it directly because gcc-multilib is not available - # for arm64 -- sudo apt install -y gcc-multilib -+ sudo apt update && sudo apt install -y gcc-multilib - fi - fi - } -diff --git a/.ci/linux-util.sh b/.ci/linux-util.sh -new file mode 100755 -index 000000000..920345123 ---- /dev/null -+++ b/.ci/linux-util.sh -@@ -0,0 +1,19 @@ -+#!/bin/bash -+ -+function free_up_disk_space_ubuntu() -+{ -+ local pkgs='azure-cli aspnetcore-* dotnet-* ghc-* firefox* -+ google-chrome-stable google-cloud-cli libmono-* llvm-* -+ microsoft-edge-stable mono-* msbuild mysql-server-core-* -+ php-* php7* powershell* temurin-* zulu-*' -+ -+ # Use apt patterns to only select real packages that match the names -+ # in the list above. -+ local pkgs=$(echo $pkgs | sed 's/[^ ]* */~n&/g') -+ -+ sudo apt update && sudo apt-get --auto-remove -y purge $pkgs -+ -+ local paths='/usr/local/lib/android/ /usr/share/dotnet/ /opt/ghc/ -+ /usr/local/share/boost/' -+ sudo rm -rf $paths -+} -diff --git a/.ci/ovn-kubernetes/Dockerfile b/.ci/ovn-kubernetes/Dockerfile -index 12f819017..eda8b6d02 100644 ---- a/.ci/ovn-kubernetes/Dockerfile -+++ b/.ci/ovn-kubernetes/Dockerfile -@@ -81,6 +81,7 @@ RUN dnf install -y *.rpm && rm -f *.rpm - # install ovn-kubernetes binaries built in previous stage - RUN mkdir -p /usr/libexec/cni/ - COPY --from=ovnkubebuilder /root/ovn-kubernetes/go-controller/_output/go/bin/ovnkube /usr/bin/ -+COPY --from=ovnkubebuilder /root/ovn-kubernetes/go-controller/_output/go/bin/ovnkube-identity /usr/bin/ - COPY --from=ovnkubebuilder /root/ovn-kubernetes/go-controller/_output/go/bin/ovn-kube-util /usr/bin/ - COPY --from=ovnkubebuilder /root/ovn-kubernetes/go-controller/_output/go/bin/ovndbchecker /usr/bin/ - COPY --from=ovnkubebuilder /root/ovn-kubernetes/go-controller/_output/go/bin/ovn-k8s-cni-overlay /usr/libexec/cni/ovn-k8s-cni-overlay -diff --git a/.cirrus.yml b/.cirrus.yml -index bd4cd08aa..3b53c45ae 100644 ---- a/.cirrus.yml -+++ b/.cirrus.yml -@@ -1,14 +1,33 @@ --arm_unit_tests_task: -+compute_engine_instance: -+ image_project: ubuntu-os-cloud -+ image: family/ubuntu-2310-arm64 -+ architecture: arm64 -+ platform: linux -+ memory: 4G -+ -+# Run separate task for the image build, so it's running only once outside -+# the test matrix. -+build_image_task: -+ install_dependencies_script: -+ - sudo apt update -+ - sudo apt install -y podman make -+ -+ build_container_script: -+ - cd utilities/containers -+ - make ubuntu -+ - podman save -o /tmp/image.tar ovn-org/ovn-tests:ubuntu - -- arm_container: -- image: ghcr.io/ovn-org/ovn-tests:fedora -- memory: 4G -- cpu: 2 -+ upload_image_script: -+ - curl -s -X POST -T /tmp/image.tar http://$CIRRUS_HTTP_CACHE_HOST/${CIRRUS_CHANGE_IN_REPO} -+ -+arm_unit_tests_task: -+ depends_on: -+ - build_image - - env: -- ARCH: aarch64 - CIRRUS_CLONE_SUBMODULES: true - PATH: ${HOME}/bin:${HOME}/.local/bin:${PATH} -+ IMAGE_NAME: ovn-org/ovn-tests:ubuntu - matrix: - - CC: gcc - TESTSUITE: test -@@ -31,5 +50,22 @@ arm_unit_tests_task: - - name: ARM64 ${CC} ${TESTSUITE} ${TEST_RANGE} - -+ install_dependencies_script: -+ - sudo apt update -+ - sudo apt install -y podman -+ -+ # XXX This should be removed when native crun >=1.9.1 -+ update_crun_script: -+ - crun --version -+ - curl -L "https://github.com/containers/crun/releases/download/1.14.1/crun-1.14.1-linux-arm64" -o /usr/bin/crun -+ - chmod +x /usr/bin/crun -+ -+ download_cache_script: -+ - curl http://$CIRRUS_HTTP_CACHE_HOST/${CIRRUS_CHANGE_IN_REPO} -o /tmp/image.tar -+ -+ load_image_script: -+ - podman load -i /tmp/image.tar -+ - rm -rf /tmp/image.tar -+ - build_script: -- - ./.ci/linux-build.sh -+ - ./.ci/ci.sh --archive-logs -diff --git a/.github/workflows/containers.yml b/.github/workflows/containers.yml -index 57e815ed8..87e28d645 100644 ---- a/.github/workflows/containers.yml -+++ b/.github/workflows/containers.yml -@@ -15,12 +15,12 @@ env: - - jobs: - container: -- runs-on: ubuntu-latest -+ runs-on: ubuntu-22.04 - strategy: - matrix: - distro: [ fedora, ubuntu ] - steps: -- - uses: actions/checkout@v3 -+ - uses: actions/checkout@v4 - - - name: Update APT cache - run: sudo apt update -diff --git a/.github/workflows/ovn-fake-multinode-tests.yml b/.github/workflows/ovn-fake-multinode-tests.yml -index 75c5ca818..79b6c4253 100644 ---- a/.github/workflows/ovn-fake-multinode-tests.yml -+++ b/.github/workflows/ovn-fake-multinode-tests.yml -@@ -13,7 +13,7 @@ concurrency: - jobs: - build: - name: Build ovn-fake-multinode image -- runs-on: ubuntu-latest -+ runs-on: ubuntu-22.04 - strategy: - matrix: - cfg: -@@ -26,7 +26,7 @@ jobs: - XDG_RUNTIME_DIR: '' - steps: - - name: Check out ovn-fake-multi-node -- uses: actions/checkout@v3 -+ uses: actions/checkout@v4 - with: - repository: 'ovn-org/ovn-fake-multinode' - path: 'ovn-fake-multinode' -@@ -36,14 +36,14 @@ jobs: - # ovn-fake-multinode builds and installs ovs from ovn-fake-multinode/ovs - # and it builds and installs ovn from ovn-fake-multinode/ovn. It uses the ovs submodule for ovn compilation. - - name: Check out ovs master -- uses: actions/checkout@v3 -+ uses: actions/checkout@v4 - with: - path: 'ovn-fake-multinode/ovs' - repository: 'openvswitch/ovs' - ref: 'master' - - - name: Check out ovn ${{ matrix.cfg.branch }} -- uses: actions/checkout@v3 -+ uses: actions/checkout@v4 - with: - path: 'ovn-fake-multinode/ovn' - submodules: recursive -@@ -63,21 +63,21 @@ jobs: - sudo podman save ovn/ovn-multi-node:${{ matrix.cfg.branch }} > /tmp/_output/ovn_${{ matrix.cfg.branch }}_image.tar - working-directory: ovn-fake-multinode - -- - uses: actions/upload-artifact@v3 -+ - uses: actions/upload-artifact@v4 - with: - name: test-${{ matrix.cfg.branch }}-image - path: /tmp/_output/ovn_${{ matrix.cfg.branch }}_image.tar - - multinode-tests: -- runs-on: ubuntu-latest -+ runs-on: ubuntu-22.04 - timeout-minutes: 15 - needs: [build] - strategy: - fail-fast: false - matrix: - cfg: -- - { branch: "main" } -- - { branch: "branch-22.03" } -+ - { branch: "main", testsuiteflags: ""} -+ - { branch: "branch-22.03", testsuiteflags: "-k 'basic test'" } - name: multinode tests ${{ join(matrix.cfg.*, ' ') }} - env: - RUNC_CMD: podman -@@ -99,19 +99,24 @@ jobs: - XDG_RUNTIME_DIR: '' - - steps: -+ - name: Check out ovn -+ uses: actions/checkout@v4 -+ - - name: install required dependencies - run: | - sudo apt update || true - sudo apt install -y ${{ env.dependencies }} - - - name: Free up disk space -- run: sudo eatmydata apt-get remove --auto-remove -y aspnetcore-* dotnet-* libmono-* mono-* msbuild php-* php7* ghc-* zulu-* -+ run: | -+ . .ci/linux-util.sh -+ free_up_disk_space_ubuntu - -- - uses: actions/download-artifact@v3 -+ - uses: actions/download-artifact@v4 - with: - name: test-main-image - -- - uses: actions/download-artifact@v3 -+ - uses: actions/download-artifact@v4 - with: - name: test-branch-22.03-image - -@@ -121,7 +126,7 @@ jobs: - sudo podman load --input ovn_branch-22.03_image.tar - - - name: Check out ovn-fake-multi-node -- uses: actions/checkout@v3 -+ uses: actions/checkout@v4 - with: - repository: 'ovn-org/ovn-fake-multinode' - path: 'ovn-fake-multinode' -@@ -132,6 +137,14 @@ jobs: - sudo systemctl start openvswitch-switch - sudo ovs-vsctl show - -+ # XXX This should be removed when native crun >=1.9.1 -+ - name: update crun script -+ run: | -+ crun --version -+ sudo curl -L "https://github.com/containers/crun/releases/download/1.14.1/crun-1.14.1-linux-amd64" -o /usr/bin/crun -+ sudo chmod +x /usr/bin/crun -+ echo "New crun version: "$(crun --version) -+ - - name: Start basic cluster - run: | - sudo -E ./ovn_cluster.sh start -@@ -151,12 +164,12 @@ jobs: - echo "$HOME/.local/bin" >> $GITHUB_PATH - - - name: set up python -- uses: actions/setup-python@v4 -+ uses: actions/setup-python@v5 - with: -- python-version: '3.x' -+ python-version: '3.12' - - - name: Check out ovn -- uses: actions/checkout@v3 -+ uses: actions/checkout@v4 - with: - path: 'ovn' - submodules: recursive -@@ -171,7 +184,7 @@ jobs: - - - name: Run fake-multinode system tests - run: | -- if ! sudo make check-multinode; then -+ if ! sudo make check-multinode TESTSUITEFLAGS="${{ matrix.cfg.testsuiteflags }}"; then - sudo podman exec -it ovn-central ovn-nbctl show || : - sudo podman exec -it ovn-central ovn-sbctl show || : - sudo podman exec -it ovn-chassis-1 ovs-vsctl show || : -@@ -185,9 +198,9 @@ jobs: - - name: copy logs on failure - if: failure() || cancelled() - run: | -- # upload-artifact@v3 throws exceptions if it tries to upload socket -+ # upload-artifact throws exceptions if it tries to upload socket - # files and we could have some socket files in testsuite.dir. -- # Also, upload-artifact@v3 doesn't work well enough with wildcards. -+ # Also, upload-artifact doesn't work well enough with wildcards. - # So, we're just archiving everything here to avoid any issues. - mkdir logs - cp ovn/config.log ./logs/ -@@ -198,7 +211,7 @@ jobs: - - - name: upload logs on failure - if: failure() || cancelled() -- uses: actions/upload-artifact@v3 -+ uses: actions/upload-artifact@v4 - with: - name: logs-linux-${{ join(matrix.cfg.*, '-') }} - path: logs.tgz -diff --git a/.github/workflows/ovn-kubernetes.yml b/.github/workflows/ovn-kubernetes.yml -index 69ab0566d..0f2b30497 100644 ---- a/.github/workflows/ovn-kubernetes.yml -+++ b/.github/workflows/ovn-kubernetes.yml -@@ -24,7 +24,7 @@ env: - jobs: - build: - name: Build -- runs-on: ubuntu-latest -+ runs-on: ubuntu-22.04 - steps: - - name: Enable Docker experimental features - run: | -@@ -32,12 +32,12 @@ jobs: - sudo service docker restart - - - name: Check out ovn -- uses: actions/checkout@v3 -+ uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Check out ovn-kubernetes -- uses: actions/checkout@v3 -+ uses: actions/checkout@v4 - with: - path: src/github.com/ovn-org/ovn-kubernetes - repository: ovn-org/ovn-kubernetes -@@ -54,7 +54,7 @@ jobs: - mkdir /tmp/_output - docker save ovn-daemonset-f:dev > /tmp/_output/image.tar - -- - uses: actions/upload-artifact@v3 -+ - uses: actions/upload-artifact@v4 - with: - name: test-image - path: /tmp/_output/image.tar -@@ -62,7 +62,7 @@ jobs: - e2e: - name: e2e - if: github.event_name != 'schedule' -- runs-on: ubuntu-latest -+ runs-on: ubuntu-22.04 - timeout-minutes: 220 - strategy: - fail-fast: false -@@ -95,20 +95,16 @@ jobs: - KIND_IPV6_SUPPORT: "${{ matrix.ipfamily == 'IPv6' || matrix.ipfamily == 'dualstack' }}" - steps: - -+ - name: Check out ovn -+ uses: actions/checkout@v4 -+ - - name: Free up disk space - run: | -- sudo eatmydata apt-get purge --auto-remove -y \ -- azure-cli aspnetcore-* dotnet-* ghc-* firefox \ -- google-chrome-stable google-cloud-sdk \ -- llvm-* microsoft-edge-stable mono-* \ -- msbuild mysql-server-core-* php-* php7* \ -- powershell temurin-* zulu-* -- -- - name: Check out ovn -- uses: actions/checkout@v3 -+ . .ci/linux-util.sh -+ free_up_disk_space_ubuntu - - - name: Check out ovn-kubernetes -- uses: actions/checkout@v3 -+ uses: actions/checkout@v4 - with: - path: src/github.com/ovn-org/ovn-kubernetes - repository: ovn-org/ovn-kubernetes -@@ -118,9 +114,10 @@ jobs: - .ci/ovn-kubernetes/prepare.sh src/github.com/ovn-org/ovn-kubernetes $GITHUB_ENV - - - name: Set up Go -- uses: actions/setup-go@v3 -+ uses: actions/setup-go@v5 - with: - go-version: ${{ env.GO_VERSION }} -+ cache-dependency-path: "**/*.sum" - id: go - - - name: Set up GOPATH -@@ -135,7 +132,7 @@ jobs: - run: | - sudo ufw disable - -- - uses: actions/download-artifact@v3 -+ - uses: actions/download-artifact@v4 - with: - name: test-image - -@@ -159,7 +156,7 @@ jobs: - - - name: Upload Junit Reports - if: always() -- uses: actions/upload-artifact@v3 -+ uses: actions/upload-artifact@v4 - with: - name: kind-junit-${{ env.JOB_NAME }}-${{ github.run_id }} - path: 'src/github.com/ovn-org/ovn-kubernetes/test/_artifacts/*.xml' -@@ -173,7 +170,7 @@ jobs: - - - name: Upload logs - if: always() -- uses: actions/upload-artifact@v3 -+ uses: actions/upload-artifact@v4 - with: - name: kind-logs-${{ env.JOB_NAME }}-${{ github.run_id }} - path: /tmp/kind/logs diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml -index fe2a14c40..85916548a 100644 +index 85916548a..5cd0babee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml -@@ -26,7 +26,7 @@ jobs: - - steps: - - name: checkout -- uses: actions/checkout@v3 -+ uses: actions/checkout@v4 - - - name: update PATH +@@ -230,6 +230,14 @@ jobs: + sudo chmod +x /usr/bin/crun + echo "New crun version: "$(crun --version) + ++ - name: Reduce ASLR entropy ++ if: matrix.cfg.sanitizers != '' ++ # Asan in llvm 14 provided in ubuntu-22.04 is incompatible with ++ # high-entropy ASLR configured in much newer kernels that GitHub ++ # runners are using leading to random crashes: ++ # https://github.com/actions/runner-images/issues/9491 ++ run: sudo sysctl -w vm.mmap_rnd_bits=28 ++ + - name: load image run: | -@@ -54,14 +54,14 @@ jobs: - - - name: cache - id: dpdk_cache -- uses: actions/cache@v3 -+ uses: actions/cache@v4 - with: - path: dpdk-dir - key: ${{ steps.gen_dpdk_key.outputs.key }} - - - name: set up python - if: steps.dpdk_cache.outputs.cache-hit != 'true' -- uses: actions/setup-python@v4 -+ uses: actions/setup-python@v5 - with: - python-version: '3.9' - -@@ -80,10 +80,62 @@ jobs: - if: steps.dpdk_cache.outputs.cache-hit != 'true' - run: ./.ci/dpdk-build.sh - -+ prepare-container: -+ # This job has the following matrix, x: Job trigger, y: Branch -+ # (scheduled jobs run only on main): -+ # +-------+-------------------+-------------------+ -+ # | | Push/Pull request | Scheduled | -+ # +-------+-------------------+-------------------+ -+ # | main | ghcr.io - Ubuntu | ghcr.io - Fedora | -+ # +-------+-------------------+-------------------+ -+ # | !main | Builds - Ubuntu | xxxxxxxxxxxxxxxxx | -+ # +-------+-------------------+-------------------+ -+ env: -+ DEPENDENCIES: podman -+ name: Prepare container -+ runs-on: ubuntu-22.04 -+ -+ steps: -+ - uses: actions/checkout@v4 -+ -+ - name: Update APT cache -+ run: sudo apt update -+ -+ - name: Install dependencies -+ run: sudo apt install -y ${{ env.DEPENDENCIES }} -+ -+ - name: Choose image distro -+ if: github.event_name == 'push' || github.event_name == 'pull_request' -+ run: | -+ echo "IMAGE_DISTRO=ubuntu" >> $GITHUB_ENV -+ -+ - name: Choose image distro -+ if: github.event_name == 'schedule' -+ run: | -+ echo "IMAGE_DISTRO=fedora" >> $GITHUB_ENV -+ -+ - name: Build container -+ if: github.ref_name != 'main' -+ run: make ${{ env.IMAGE_DISTRO }} -+ working-directory: utilities/containers -+ -+ - name: Download container -+ if: github.ref_name == 'main' -+ run: podman pull ghcr.io/ovn-org/ovn-tests:${{ env.IMAGE_DISTRO }} -+ -+ - name: Export image -+ run: podman save -o /tmp/image.tar ovn-org/ovn-tests -+ -+ - name: Cache image -+ id: image_cache -+ uses: actions/cache@v4 -+ with: -+ path: /tmp/image.tar -+ key: ${{ github.sha }} -+ - build-linux: -- needs: build-dpdk -+ needs: [build-dpdk, prepare-container] - env: -- IMAGE_NAME: ghcr.io/ovn-org/ovn-tests:ubuntu - ARCH: ${{ matrix.cfg.arch }} - CC: ${{ matrix.cfg.compiler }} - DPDK: ${{ matrix.cfg.dpdk }} -@@ -94,7 +146,7 @@ jobs: - SANITIZERS: ${{ matrix.cfg.sanitizers }} - - name: linux ${{ join(matrix.cfg.*, ' ') }} -- runs-on: ubuntu-latest -+ runs-on: ubuntu-22.04 - - strategy: - fail-fast: false -@@ -130,20 +182,20 @@ jobs: - steps: - - name: checkout - if: github.event_name == 'push' || github.event_name == 'pull_request' -- uses: actions/checkout@v3 -+ uses: actions/checkout@v4 - with: - submodules: recursive - - # For weekly runs, don't update submodules - - name: checkout without submodule - if: github.event_name == 'schedule' -- uses: actions/checkout@v3 -+ uses: actions/checkout@v4 - - # Weekly runs test using the tip of the most recent stable OVS branch - # instead of the submodule. - - name: checkout OVS - if: github.event_name == 'schedule' -- uses: actions/checkout@v3 -+ uses: actions/checkout@v4 - with: - repository: 'openvswitch/ovs' - fetch-depth: 0 -@@ -157,13 +209,33 @@ jobs: - sort -V | tail -1) - working-directory: ovs - -- - name: cache -+ - name: cache dpdk - if: matrix.cfg.dpdk != '' -- uses: actions/cache@v3 -+ uses: actions/cache@v4 - with: - path: dpdk-dir - key: ${{ needs.build-dpdk.outputs.dpdk_key }} - -+ - name: image cache -+ uses: actions/cache@v4 -+ with: -+ path: /tmp/image.tar -+ key: ${{ github.sha }} -+ -+ # XXX This should be removed when native crun >=1.9.1 -+ - name: update crun script -+ run: | -+ crun --version -+ sudo curl -L "https://github.com/containers/crun/releases/download/1.14.1/crun-1.14.1-linux-amd64" -o /usr/bin/crun -+ sudo chmod +x /usr/bin/crun -+ echo "New crun version: "$(crun --version) -+ -+ - name: load image -+ run: | -+ sudo podman load -i /tmp/image.tar -+ podman load -i /tmp/image.tar -+ rm -rf /tmp/image.tar -+ - - name: build - if: ${{ startsWith(matrix.cfg.testsuite, 'system-test') }} - run: sudo -E ./.ci/ci.sh --archive-logs -@@ -174,7 +246,7 @@ jobs: - - - name: upload logs on failure - if: failure() || cancelled() -- uses: actions/upload-artifact@v3 -+ uses: actions/upload-artifact@v4 - with: - name: logs-linux-${{ join(matrix.cfg.*, '-') }} - path: logs.tgz -@@ -193,18 +265,18 @@ jobs: - steps: - - name: checkout - if: github.event_name == 'push' || github.event_name == 'pull_request' -- uses: actions/checkout@v3 -+ uses: actions/checkout@v4 - with: - submodules: recursive - # For weekly runs, don't update submodules - - name: checkout without submodule - if: github.event_name == 'schedule' -- uses: actions/checkout@v3 -+ uses: actions/checkout@v4 - # Weekly runs test using the tip of the most recent stable OVS branch - # instead of the submodule. - - name: checkout OVS - if: github.event_name == 'schedule' -- uses: actions/checkout@v3 -+ uses: actions/checkout@v4 - with: - repository: 'openvswitch/ovs' - fetch-depth: 0 -@@ -223,24 +295,24 @@ jobs: - echo "$HOME/bin" >> $GITHUB_PATH - echo "$HOME/.local/bin" >> $GITHUB_PATH - - name: set up python -- uses: actions/setup-python@v4 -+ uses: actions/setup-python@v5 - with: -- python-version: '3.x' -+ python-version: '3.12' - - name: prepare - run: ./.ci/osx-prepare.sh - - name: build - run: ./.ci/osx-build.sh - - name: upload logs on failure - if: failure() -- uses: actions/upload-artifact@v3 -+ uses: actions/upload-artifact@v4 - with: - name: logs-osx-clang---disable-ssl - path: config.log - - build-linux-rpm: - name: linux rpm fedora -- runs-on: ubuntu-latest -- container: fedora:latest -+ runs-on: ubuntu-22.04 -+ container: fedora:38 - timeout-minutes: 30 - - strategy: -@@ -251,7 +323,7 @@ jobs: - run: dnf install -y dnf-plugins-core git rpm-build - - - name: checkout -- uses: actions/checkout@v3 -+ uses: actions/checkout@v4 - with: - submodules: recursive - -@@ -279,7 +351,7 @@ jobs: - run: make rpm-fedora - - - name: upload rpm packages -- uses: actions/upload-artifact@v3 -+ uses: actions/upload-artifact@v4 - with: - name: rpm-packages - path: | -diff --git a/.readthedocs.yaml b/.readthedocs.yaml -new file mode 100644 -index 000000000..8c451663a ---- /dev/null -+++ b/.readthedocs.yaml -@@ -0,0 +1,26 @@ -+# .readthedocs.yaml -+# Read the Docs configuration file. -+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details. -+ -+# Required. -+version: 2 -+ -+# Set the OS, Python version, etc. -+build: -+ os: ubuntu-22.04 -+ tools: -+ python: "3.12" -+ -+# Build documentation in the "Documentation/" directory with Sphinx. -+sphinx: -+ configuration: Documentation/conf.py -+ # Default HTML builder. -+ builder: "html" -+ -+# Build all formats: HTML, PDF, ePub. -+formats: all -+ -+# Declare the Python requirements. -+python: -+ install: -+ - requirements: Documentation/requirements.txt -diff --git a/Documentation/conf.py b/Documentation/conf.py -index f7eceaec8..f8fc0125f 100644 ---- a/Documentation/conf.py -+++ b/Documentation/conf.py -@@ -12,16 +12,14 @@ - # All configuration values have a default; values that are commented out - # serve to show the default. - -+import importlib - import string - import sys - --try: -- import ovs_sphinx_theme -- use_ovs_theme = True --except ImportError: -- print("Cannot find 'ovs-sphinx-theme' package. " -+use_rtd_theme = importlib.util.find_spec('sphinx_rtd_theme') is not None -+if not use_rtd_theme: -+ print("Cannot find 'sphinx_rtd_theme' package. " - "Falling back to default theme.") -- use_ovs_theme = False - - # -- General configuration ------------------------------------------------ - -@@ -48,7 +46,7 @@ master_doc = 'contents' - - # General information about the project. - project = u'Open Virtual Network (OVN)' --copyright = u'2020, The Open Virtual Network (OVN) Development Community' -+copyright = u'2020-2023, The Open Virtual Network (OVN) Development Community' - author = u'The Open Virtual Network (OVN) Development Community' - - # The version info for the project you're documenting, acts as replacement for -@@ -89,14 +87,8 @@ linkcheck_anchors = False - # The theme to use for HTML and HTML Help pages. See the documentation for - # a list of builtin themes. - # --if use_ovs_theme: -- html_theme = 'ovs' -- --# Add any paths that contain custom themes here, relative to this directory. --if use_ovs_theme: -- html_theme_path = [ovs_sphinx_theme.get_theme_dir()] --else: -- html_theme_path = [] -+if use_rtd_theme: -+ html_theme = 'sphinx_rtd_theme' - - # The name of an image file (relative to this directory) to place at the top - # of the sidebar. -diff --git a/Documentation/internals/documentation.rst b/Documentation/internals/documentation.rst -index 72a120bef..59c18b3a2 100644 ---- a/Documentation/internals/documentation.rst -+++ b/Documentation/internals/documentation.rst -@@ -41,17 +41,13 @@ variety of other output formats but also allows for things like - cross-referencing and indexing. for more information on the two, refer to the - :doc:`contributing/documentation-style`. - --ovs-sphinx-theme -+sphinx_rtd_theme - ---------------- - --The documentation uses its own theme, `ovs-sphinx-theme`, which can be found on --GitHub__ and is published on pypi__. This is shared by Open vSwitch and OVN. --It is packaged separately to ensure all documentation gets the latest version --of the theme (assuming there are no major version bumps in that package). If --building locally and the package is installed, it will be used. If the package --is not installed, Sphinx will fallback to the default theme. -- --The package is currently maintained by Stephen Finucane and Russell Bryant. -+The documentation uses `sphinx_rtd_theme`, which can be found on GitHub__ and -+is published on pypi__. It is also packaged in major distributions. -+If building locally and the package is installed, it will be used. If the -+package is not installed, Sphinx will fallback to the default theme. - - Read the Docs - ------------- -@@ -72,6 +68,6 @@ modifications to this site, refer to the `GitHub project`__. - - __ http://docutils.sourceforge.net/rst.html - __ http://www.sphinx-doc.org/ --__ https://github.com/openvswitch/ovs-sphinx-theme --__ https://pypi.python.org/pypi/ovs-sphinx-theme -+__ https://github.com/readthedocs/sphinx_rtd_theme -+__ https://pypi.python.org/pypi/sphinx_rtd_theme - __ https://github.com/ovn-org/ovn-org.github.io -diff --git a/Documentation/internals/release-process.rst b/Documentation/internals/release-process.rst -index ec79fe48c..26d3f8d4d 100644 ---- a/Documentation/internals/release-process.rst -+++ b/Documentation/internals/release-process.rst -@@ -64,6 +64,10 @@ Scheduling`_ for the timing of each stage: - branch. Features to be added to release branches should be limited in scope - and risk and discussed on ovs-dev before creating the branch. - -+ In order to keep the CI stable on the new release branch, the Ubuntu -+ container should be pinned to the current LTS version in the Dockerfile -+ e.g. registry.hub.docker.com/library/ubuntu:22.04. -+ - 3. When committers come to rough consensus that the release is ready, they - release the .0 release on its branch, e.g. 25.09.0 for branch-25.09. To - make the actual release, a committer pushes a signed tag named, e.g. -diff --git a/Documentation/intro/install/general.rst b/Documentation/intro/install/general.rst -index 589518846..dd8bf5c2c 100644 ---- a/Documentation/intro/install/general.rst -+++ b/Documentation/intro/install/general.rst -@@ -134,10 +134,7 @@ following to obtain better warnings: - - - clang, version 3.4 or later - --- flake8 along with the hacking flake8 plugin (for Python code). The automatic -- flake8 check that runs against Python code has some warnings enabled that -- come from the "hacking" flake8 plugin. If it's not installed, the warnings -- just won't occur until it's run on a system with "hacking" installed. -+- flake8 (for Python code) - - You may find the ovs-dev script found in ``ovs/utilities/ovs-dev.py`` useful. - -diff --git a/Documentation/requirements.txt b/Documentation/requirements.txt -index 77130c6e0..63a7997f7 100644 ---- a/Documentation/requirements.txt -+++ b/Documentation/requirements.txt -@@ -1,2 +1,2 @@ --sphinx>=1.1,<2.0 --ovs_sphinx_theme>=1.0,<1.1 -+sphinx>=1.1 -+sphinx_rtd_theme>=1.0,<2.0 -diff --git a/Documentation/tutorials/ovn-sandbox.rst b/Documentation/tutorials/ovn-sandbox.rst -index 2b574c02f..decc8abb3 100644 ---- a/Documentation/tutorials/ovn-sandbox.rst -+++ b/Documentation/tutorials/ovn-sandbox.rst -@@ -162,16 +162,16 @@ to OpenFlow flows programmed by ``ovn-controller``. See the `ovn-trace(8)`_ - man page for more detail. - - --.. _ovn-architecture: http://openvswitch.org/support/dist-docs/ovn-architecture.7.html --.. _ovn-nb(5): http://openvswitch.org/support/dist-docs/ovn-nb.5.html --.. _ovn-sb(5): http://openvswitch.org/support/dist-docs/ovn-sb.5.html -+.. _ovn-architecture: http://www.ovn.org/support/dist-docs/ovn-architecture.7.html -+.. _ovn-nb(5): http://www.ovn.org/support/dist-docs/ovn-nb.5.html -+.. _ovn-sb(5): http://www.ovn.org/support/dist-docs/ovn-sb.5.html - .. _vtep(5): http://openvswitch.org/support/dist-docs/vtep.5.html --.. _ovn-northd(8): http://openvswitch.org/support/dist-docs/ovn-northd.8.html --.. _ovn-controller(8): http://openvswitch.org/support/dist-docs/ovn-controller.8.html --.. _ovn-controller-vtep(8): http://openvswitch.org/support/dist-docs/ovn-controller-vtep.8.html -+.. _ovn-northd(8): http://www.ovn.org/support/dist-docs/ovn-northd.8.html -+.. _ovn-controller(8): http://www.ovn.org/support/dist-docs/ovn-controller.8.html -+.. _ovn-controller-vtep(8): http://www.ovn.org/support/dist-docs/ovn-controller-vtep.8.html - .. _vtep-ctl(8): http://openvswitch.org/support/dist-docs/vtep-ctl.8.html --.. _ovn-nbctl(8): http://openvswitch.org/support/dist-docs/ovn-nbctl.8.html --.. _ovn-sbctl(8): http://openvswitch.org/support/dist-docs/ovn-sbctl.8.html --.. _ovn-trace(8): http://openvswitch.org/support/dist-docs/ovn-trace.8.html -+.. _ovn-nbctl(8): http://www.ovn.org/support/dist-docs/ovn-nbctl.8.html -+.. _ovn-sbctl(8): http://www.ovn.org/support/dist-docs/ovn-sbctl.8.html -+.. _ovn-trace(8): http://www.ovn.org/support/dist-docs/ovn-trace.8.html - .. _ovs-advanced: https://github.com/openvswitch/ovs/blob/master/Documentation/tutorials/ovs-advanced.rst - -diff --git a/Makefile.am b/Makefile.am -index b58d4a501..bfc9565e8 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -90,6 +90,7 @@ EXTRA_DIST = \ - .ci/dpdk-build.sh \ - .ci/dpdk-prepare.sh \ - .ci/linux-build.sh \ -+ .ci/linux-util.sh \ - .ci/osx-build.sh \ - .ci/osx-prepare.sh \ - .ci/ovn-kubernetes/Dockerfile \ -@@ -99,6 +100,7 @@ EXTRA_DIST = \ - .github/workflows/test.yml \ - .github/workflows/ovn-kubernetes.yml \ - .github/workflows/ovn-fake-multinode-tests.yml \ -+ .readthedocs.yaml \ - boot.sh \ - $(MAN_FRAGMENTS) \ - $(MAN_ROOTS) \ -@@ -414,16 +416,10 @@ ALL_LOCAL += flake8-check - # F811 redefinition of unused from line (only from flake8 v2.0) - # D*** -- warnings from flake8-docstrings plugin - # H*** -- warnings from flake8 hacking plugin (custom style checks beyond PEP8) --# H231 Python 3.x incompatible 'except x,y:' construct --# H232 Python 3.x incompatible octal 077 should be written as 0o77 --# H233 Python 3.x incompatible use of print operator --# H238 old style class declaration, use new style (inherit from `object`) --FLAKE8_SELECT = H231,H232,H233,H238 - FLAKE8_IGNORE = E121,E123,E125,E126,E127,E128,E129,E131,E722,W503,W504,F811,D,H,I - flake8-check: $(FLAKE8_PYFILES) - $(FLAKE8_WERROR)$(AM_V_GEN) \ - src='$^' && \ -- flake8 $$src --select=$(FLAKE8_SELECT) $(FLAKE8_FLAGS) && \ - flake8 $$src --ignore=$(FLAKE8_IGNORE) $(FLAKE8_FLAGS) && \ - touch $@ - endif + sudo podman load -i /tmp/image.tar diff --git a/NEWS b/NEWS -index 75e046ab3..58b1c9066 100644 +index 31c069aea..97e1c41d5 100644 --- a/NEWS +++ b/NEWS -@@ -1,3 +1,15 @@ -+OVN v23.09.3 - xx xxx xxxx -+-------------------------- -+ -+OVN v23.09.2 - 01 Mar 2024 -+-------------------------- -+ - Bug fixes -+ - Enable PMTU discovery on geneve/vxlan tunnels for E/W traffic. -+ -+OVN v23.09.1 - 01 Dec 2023 +@@ -1,3 +1,6 @@ ++OVN v23.09.4 - xx xxx xxxx +-------------------------- -+ - Bug fixes + - OVN v23.09.0 - 15 Sep 2023 - ---------------------------- - - Added FDB aging mechanism, that is disabled by default. + OVN v23.09.3 - 12 Mar 2024 + -------------------------- + - Bug fixes diff --git a/configure.ac b/configure.ac -index ab404b959..090a29a15 100644 +index 090a29a15..c71ade236 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # limitations under the License. AC_PREREQ(2.63) --AC_INIT(ovn, 23.09.0, bugs@openvswitch.org) -+AC_INIT(ovn, 23.09.3, bugs@openvswitch.org) +-AC_INIT(ovn, 23.09.3, bugs@openvswitch.org) ++AC_INIT(ovn, 23.09.4, bugs@openvswitch.org) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([config.h]) -diff --git a/controller-vtep/ovn-controller-vtep.c b/controller-vtep/ovn-controller-vtep.c -index 23b368179..4472e5285 100644 ---- a/controller-vtep/ovn-controller-vtep.c -+++ b/controller-vtep/ovn-controller-vtep.c -@@ -306,10 +306,12 @@ parse_options(int argc, char *argv[]) - - switch (c) { - case 'd': -+ free(ovnsb_remote); - ovnsb_remote = xstrdup(optarg); - break; - - case 'D': -+ free(vtep_remote); - vtep_remote = xstrdup(optarg); - break; - -diff --git a/controller/bfd.c b/controller/bfd.c -index cf011e382..f47333191 100644 ---- a/controller/bfd.c -+++ b/controller/bfd.c -@@ -235,6 +235,9 @@ bfd_run(const struct ovsrec_interface_table *interface_table, - if (mult) { - smap_add(&bfd, "mult", mult); - } -+ /* `check_tnl_key` must always be set to "true" to avoid processing of -+ * BFD control messages originating from a logical port. */ -+ smap_add(&bfd, "check_tnl_key", "true"); - } - - /* Enable or disable bfd */ -diff --git a/controller/binding.c b/controller/binding.c -index a521f2828..2afc5d48a 100644 ---- a/controller/binding.c -+++ b/controller/binding.c -@@ -55,8 +55,13 @@ struct claimed_port { - long long int last_claimed; - }; - -+struct qos_port { -+ bool added; -+}; -+ - static struct shash _claimed_ports = SHASH_INITIALIZER(&_claimed_ports); - static struct sset _postponed_ports = SSET_INITIALIZER(&_postponed_ports); -+static struct shash _qos_ports = SHASH_INITIALIZER(&_qos_ports); - - static void - remove_additional_chassis(const struct sbrec_port_binding *pb, -@@ -218,6 +223,17 @@ get_qos_egress_port_interface(struct shash *bridge_mappings, - return NULL; - } - -+static void -+add_or_del_qos_port(const char *ovn_port, bool add) -+{ -+ struct qos_port *qos_port = shash_find_data(&_qos_ports, ovn_port); -+ if (!qos_port) { -+ qos_port = xzalloc(sizeof *qos_port); -+ shash_add(&_qos_ports, ovn_port, qos_port); -+ } -+ qos_port->added = add; -+} -+ - /* 34359738360 == (2^32 - 1) * 8. netdev_set_qos() doesn't support - * 64-bit rate netlink attributes, so the maximum value is 2^32 - 1 - * bytes. The 'max-rate' config option is in bits, so multiplying by 8. -@@ -225,7 +241,7 @@ get_qos_egress_port_interface(struct shash *bridge_mappings, - * can be unrecognized for certain NICs or reported too low for virtual - * interfaces. */ - #define OVN_QOS_MAX_RATE 34359738360ULL --static void -+static bool - add_ovs_qos_table_entry(struct ovsdb_idl_txn *ovs_idl_txn, - const struct ovsrec_port *port, - unsigned long long min_rate, -@@ -239,7 +255,7 @@ add_ovs_qos_table_entry(struct ovsdb_idl_txn *ovs_idl_txn, - const struct ovsrec_qos *qos = port->qos; - if (qos && !smap_get_bool(&qos->external_ids, "ovn_qos", false)) { - /* External configured QoS, do not overwrite it. */ -- return; -+ return false; - } - - if (!qos) { -@@ -282,22 +298,18 @@ add_ovs_qos_table_entry(struct ovsdb_idl_txn *ovs_idl_txn, - ovsrec_queue_verify_external_ids(queue); - ovsrec_queue_set_external_ids(queue, &external_ids); - smap_destroy(&external_ids); -+ return true; - } - - static void --remove_stale_qos_entry(struct ovsdb_idl_txn *ovs_idl_txn, -- const struct sbrec_port_binding *pb, -+remove_stale_qos_entry( const char *logical_port, - struct ovsdb_idl_index *ovsrec_port_by_qos, - const struct ovsrec_qos_table *qos_table, - struct hmap *queue_map) - { -- if (!ovs_idl_txn) { -- return; -- } -- - struct qos_queue *q = find_qos_queue( -- queue_map, hash_string(pb->logical_port, 0), -- pb->logical_port); -+ queue_map, hash_string(logical_port, 0), -+ logical_port); - if (!q) { - return; - } -@@ -338,8 +350,12 @@ remove_stale_qos_entry(struct ovsdb_idl_txn *ovs_idl_txn, - - static void - configure_qos(const struct sbrec_port_binding *pb, -- struct binding_ctx_in *b_ctx_in, -- struct binding_ctx_out *b_ctx_out) -+ struct ovsdb_idl_txn *ovs_idl_txn, -+ struct ovsdb_idl_index *ovsrec_port_by_qos, -+ const struct ovsrec_qos_table *qos_table, -+ struct hmap *qos_map, -+ const struct ovsrec_open_vswitch_table *ovs_table, -+ const struct ovsrec_bridge_table *bridge_table) - { - unsigned long long min_rate = smap_get_ullong( - &pb->options, "qos_min_rate", 0); -@@ -351,20 +367,20 @@ configure_qos(const struct sbrec_port_binding *pb, - - if ((!min_rate && !max_rate && !burst) || !queue_id) { - /* Qos is not configured for this port. */ -- remove_stale_qos_entry(b_ctx_in->ovs_idl_txn, pb, -- b_ctx_in->ovsrec_port_by_qos, -- b_ctx_in->qos_table, b_ctx_out->qos_map); -+ remove_stale_qos_entry(pb->logical_port, -+ ovsrec_port_by_qos, -+ qos_table, qos_map); - return; - } - - const char *network = smap_get(&pb->options, "qos_physical_network"); - uint32_t hash = hash_string(pb->logical_port, 0); -- struct qos_queue *q = find_qos_queue(b_ctx_out->qos_map, hash, -+ struct qos_queue *q = find_qos_queue(qos_map, hash, - pb->logical_port); - if (!q || q->min_rate != min_rate || q->max_rate != max_rate || - q->burst != burst || (network && strcmp(network, q->network))) { - struct shash bridge_mappings = SHASH_INITIALIZER(&bridge_mappings); -- add_ovs_bridge_mappings(b_ctx_in->ovs_table, b_ctx_in->bridge_table, -+ add_ovs_bridge_mappings(ovs_table, bridge_table, - &bridge_mappings); - - const struct ovsrec_port *port = NULL; -@@ -375,25 +391,58 @@ configure_qos(const struct sbrec_port_binding *pb, - } - if (iface) { - /* Add new QoS entries. */ -- add_ovs_qos_table_entry(b_ctx_in->ovs_idl_txn, port, min_rate, -+ if (add_ovs_qos_table_entry(ovs_idl_txn, port, min_rate, - max_rate, burst, queue_id, -- pb->logical_port); -- if (!q) { -- q = xzalloc(sizeof *q); -- hmap_insert(b_ctx_out->qos_map, &q->node, hash); -- q->port = xstrdup(pb->logical_port); -- q->queue_id = queue_id; -+ pb->logical_port)) { -+ if (!q) { -+ q = xzalloc(sizeof *q); -+ hmap_insert(qos_map, &q->node, hash); -+ q->port = xstrdup(pb->logical_port); -+ q->queue_id = queue_id; -+ } -+ free(q->network); -+ q->network = network ? xstrdup(network) : NULL; -+ q->min_rate = min_rate; -+ q->max_rate = max_rate; -+ q->burst = burst; - } -- free(q->network); -- q->network = network ? xstrdup(network) : NULL; -- q->min_rate = min_rate; -- q->max_rate = max_rate; -- q->burst = burst; - } - shash_destroy(&bridge_mappings); - } - } - -+void -+update_qos(struct ovsdb_idl_index *sbrec_port_binding_by_name, -+ struct ovsdb_idl_txn *ovs_idl_txn, -+ struct ovsdb_idl_index *ovsrec_port_by_qos, -+ const struct ovsrec_qos_table *qos_table, -+ struct hmap *qos_map, -+ const struct ovsrec_open_vswitch_table *ovs_table, -+ const struct ovsrec_bridge_table *bridge_table) -+{ -+ /* Remove qos for any ports for which we could not do it before */ -+ const struct sbrec_port_binding *pb; -+ -+ struct shash_node *node; -+ SHASH_FOR_EACH_SAFE (node, &_qos_ports) { -+ struct qos_port *qos_port = (struct qos_port *) node->data; -+ if (qos_port->added) { -+ pb = lport_lookup_by_name(sbrec_port_binding_by_name, -+ node->name); -+ if (pb) { -+ configure_qos(pb, ovs_idl_txn, ovsrec_port_by_qos, qos_table, -+ qos_map, ovs_table, bridge_table); -+ } -+ } else { -+ remove_stale_qos_entry(node->name, -+ ovsrec_port_by_qos, -+ qos_table, qos_map); -+ } -+ free(qos_port); -+ shash_delete(&_qos_ports, node); -+ } -+} -+ - static const struct ovsrec_queue * - find_qos_queue_by_external_ids(const struct smap *external_ids, - struct ovsdb_idl_index *ovsrec_queue_by_external_ids) -@@ -1144,33 +1193,22 @@ local_binding_set_pb(struct shash *local_bindings, const char *pb_name, - * - set the 'pb.up' field to true if 'parent_pb.up' is 'true' (e.g., for - * container and virtual ports). - * -- * Returns false if lport is not claimed due to 'sb_readonly'. -- * Returns true otherwise. -- * - * Note: - * Updates the 'pb->up' field only if it's explicitly set to 'false'. - * This is to ensure compatibility with older versions of ovn-northd. - */ --static bool -+void - claimed_lport_set_up(const struct sbrec_port_binding *pb, -- const struct sbrec_port_binding *parent_pb, -- bool sb_readonly) -+ const struct sbrec_port_binding *parent_pb) - { -- /* When notify_up is false in claim_port(), no state is created -- * by if_status_mgr. In such cases, return false (i.e. trigger recompute) -- * if we can't update sb (because it is readonly). -- */ - bool up = true; - if (!parent_pb || (parent_pb->n_up && parent_pb->up[0])) { -- if (!sb_readonly) { -- if (pb->n_up) { -- sbrec_port_binding_set_up(pb, &up, 1); -- } -- } else if (pb->n_up && !pb->up[0]) { -- return false; -+ if (pb->n_up) { -+ VLOG_INFO("Setting lport %s up in Southbound", -+ pb->logical_port); -+ sbrec_port_binding_set_up(pb, &up, 1); - } - } -- return true; - } - - typedef void (*set_func)(const struct sbrec_port_binding *pb, -@@ -1250,7 +1288,7 @@ remove_additional_chassis(const struct sbrec_port_binding *pb, - remove_additional_encap_for_chassis(pb, chassis_rec); - } - --static bool -+bool - lport_maybe_postpone(const char *port_name, long long int now, - struct sset *postponed_ports) - { -@@ -1273,7 +1311,7 @@ claim_lport(const struct sbrec_port_binding *pb, - const struct sbrec_port_binding *parent_pb, - const struct sbrec_chassis *chassis_rec, - const struct ovsrec_interface *iface_rec, -- bool sb_readonly, bool notify_up, -+ bool sb_readonly, bool is_vif, - struct hmap *tracked_datapaths, - struct if_status_mgr *if_mgr, - struct sset *postponed_ports) -@@ -1298,39 +1336,27 @@ claim_lport(const struct sbrec_port_binding *pb, - } - update_tracked = true; - -- if (!notify_up) { -- if (!claimed_lport_set_up(pb, parent_pb, sb_readonly)) { -- return false; -- } -- if (sb_readonly) { -- return false; -- } -- set_pb_chassis_in_sbrec(pb, chassis_rec, true); -- } else { -- if_status_mgr_claim_iface(if_mgr, pb, chassis_rec, iface_rec, -- sb_readonly, can_bind); -- } -+ if_status_mgr_claim_iface(if_mgr, pb, chassis_rec, iface_rec, -+ sb_readonly, can_bind, is_vif, -+ parent_pb); - register_claim_timestamp(pb->logical_port, now); - sset_find_and_delete(postponed_ports, pb->logical_port); - } else { -- if (!notify_up) { -- if (!claimed_lport_set_up(pb, parent_pb, sb_readonly)) { -- return false; -- } -- } else { -- if ((pb->n_up && !pb->up[0]) || -- !smap_get_bool(&iface_rec->external_ids, -- OVN_INSTALLED_EXT_ID, false)) { -- if_status_mgr_claim_iface(if_mgr, pb, chassis_rec, -- iface_rec, sb_readonly, -- can_bind); -- } -+ update_tracked = true; -+ if ((pb->n_up && !pb->up[0]) || -+ (is_vif && !smap_get_bool(&iface_rec->external_ids, -+ OVN_INSTALLED_EXT_ID, false))) { -+ if_status_mgr_claim_iface(if_mgr, pb, chassis_rec, -+ iface_rec, sb_readonly, -+ can_bind, is_vif, -+ parent_pb); - } - } - } else if (can_bind == CAN_BIND_AS_ADDITIONAL) { - if (!is_additional_chassis(pb, chassis_rec)) { - if_status_mgr_claim_iface(if_mgr, pb, chassis_rec, iface_rec, -- sb_readonly, can_bind); -+ sb_readonly, can_bind, is_vif, -+ parent_pb); - update_tracked = true; - } - } -@@ -1524,8 +1550,8 @@ consider_vif_lport_(const struct sbrec_port_binding *pb, - tracked_datapath_lport_add(pb, TRACKED_RESOURCE_UPDATED, - b_ctx_out->tracked_dp_bindings); - } -- if (b_lport->lbinding->iface && b_ctx_in->ovs_idl_txn) { -- configure_qos(pb, b_ctx_in, b_ctx_out); -+ if (b_lport->lbinding->iface) { -+ add_or_del_qos_port(pb->logical_port, true); - } - } else { - /* We could, but can't claim the lport. */ -@@ -1814,8 +1840,10 @@ consider_nonvif_lport_(const struct sbrec_port_binding *pb, - b_ctx_out->postponed_ports); - } - -- if (pb->chassis == b_ctx_in->chassis_rec || -- is_additional_chassis(pb, b_ctx_in->chassis_rec)) { -+ if (pb->chassis == b_ctx_in->chassis_rec -+ || is_additional_chassis(pb, b_ctx_in->chassis_rec) -+ || if_status_is_port_claimed(b_ctx_out->if_mgr, -+ pb->logical_port)) { - return release_lport(pb, b_ctx_in->chassis_rec, - !b_ctx_in->ovnsb_idl_txn, - b_ctx_out->tracked_dp_bindings, -@@ -1851,7 +1879,6 @@ consider_l3gw_lport(const struct sbrec_port_binding *pb, - - static void - consider_localnet_lport(const struct sbrec_port_binding *pb, -- struct binding_ctx_in *b_ctx_in, - struct binding_ctx_out *b_ctx_out) - { - struct local_datapath *ld -@@ -1860,14 +1887,23 @@ consider_localnet_lport(const struct sbrec_port_binding *pb, - if (!ld) { - return; - } -+ -+ bool pb_localnet_learn_fdb = smap_get_bool(&pb->options, -+ "localnet_learn_fdb", false); -+ if (pb_localnet_learn_fdb != b_ctx_out->localnet_learn_fdb) { -+ b_ctx_out->localnet_learn_fdb = pb_localnet_learn_fdb; -+ if (b_ctx_out->tracked_dp_bindings) { -+ b_ctx_out->localnet_learn_fdb_changed = true; -+ tracked_datapath_lport_add(pb, TRACKED_RESOURCE_UPDATED, -+ b_ctx_out->tracked_dp_bindings); -+ } -+ } -+ - /* Add all localnet ports to local_ifaces so that we allocate ct zones - * for them. */ - update_local_lports(pb->logical_port, b_ctx_out); - -- if (b_ctx_in->ovs_idl_txn) { -- configure_qos(pb, b_ctx_in, b_ctx_out); -- } -- -+ add_or_del_qos_port(pb->logical_port, true); - update_related_lport(pb, b_ctx_out); - } - -@@ -1988,6 +2024,7 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct binding_ctx_out *b_ctx_out) - return; - } - -+ shash_clear_free_data(&_qos_ports); - struct shash bridge_mappings = SHASH_INITIALIZER(&bridge_mappings); - - if (b_ctx_in->br_int) { -@@ -2103,7 +2140,7 @@ binding_run(struct binding_ctx_in *b_ctx_in, struct binding_ctx_out *b_ctx_out) - * accordingly. */ - struct lport *lnet_lport; - LIST_FOR_EACH_POP (lnet_lport, list_node, &localnet_lports) { -- consider_localnet_lport(lnet_lport->pb, b_ctx_in, b_ctx_out); -+ consider_localnet_lport(lnet_lport->pb, b_ctx_out); - update_ld_localnet_port(lnet_lport->pb, &bridge_mappings, - b_ctx_out->local_datapaths); - free(lnet_lport); -@@ -2345,7 +2382,7 @@ consider_iface_release(const struct ovsrec_interface *iface_rec, - - lbinding = local_binding_find(local_bindings, iface_id); - -- if (lbinding) { -+ if (lbinding) { - if (lbinding->multiple_bindings) { - VLOG_INFO("Multiple bindings for %s: force recompute to clean up", - iface_id); -@@ -2365,54 +2402,50 @@ consider_iface_release(const struct ovsrec_interface *iface_rec, - return true; - } - } -- } - -- struct binding_lport *b_lport = -- local_binding_get_primary_or_localport_lport(lbinding); -- if (is_binding_lport_this_chassis(b_lport, b_ctx_in->chassis_rec)) { -- struct local_datapath *ld = -- get_local_datapath(b_ctx_out->local_datapaths, -- b_lport->pb->datapath->tunnel_key); -- if (ld) { -- remove_pb_from_local_datapath(b_lport->pb, -- b_ctx_out, ld); -- } -- -- remove_stale_qos_entry(b_ctx_in->ovs_idl_txn, b_lport->pb, -- b_ctx_in->ovsrec_port_by_qos, -- b_ctx_in->qos_table, b_ctx_out->qos_map); -+ struct binding_lport *b_lport = -+ local_binding_get_primary_or_localport_lport(lbinding); - -- /* Release the primary binding lport and other children lports if -- * any. */ -- LIST_FOR_EACH (b_lport, list_node, &lbinding->binding_lports) { -- if (!release_binding_lport(b_ctx_in->chassis_rec, b_lport, -- !b_ctx_in->ovnsb_idl_txn, -- b_ctx_out)) { -- return false; -+ if (is_binding_lport_this_chassis(b_lport, b_ctx_in->chassis_rec)) { -+ struct local_datapath *ld = -+ get_local_datapath(b_ctx_out->local_datapaths, -+ b_lport->pb->datapath->tunnel_key); -+ if (ld) { -+ remove_pb_from_local_datapath(b_lport->pb, -+ b_ctx_out, ld); - } -- } -- if (lbinding->iface && lbinding->iface->name) { -- if_status_mgr_remove_ovn_installed(b_ctx_out->if_mgr, -- lbinding->iface->name, -- &lbinding->iface->header_.uuid); -- } -+ add_or_del_qos_port(b_lport->pb->logical_port, false); - -- } else if (lbinding && b_lport && b_lport->type == LP_LOCALPORT) { -- /* lbinding is associated with a localport. Remove it from the -- * related lports. */ -- remove_related_lport(b_lport->pb, b_ctx_out); -- } -+ /* Release the primary binding lport and other children lports if -+ * any. */ -+ LIST_FOR_EACH (b_lport, list_node, &lbinding->binding_lports) { -+ if (!release_binding_lport(b_ctx_in->chassis_rec, b_lport, -+ !b_ctx_in->ovnsb_idl_txn, -+ b_ctx_out)) { -+ return false; -+ } -+ } -+ if (lbinding->iface && lbinding->iface->name) { -+ if_status_mgr_remove_ovn_installed(b_ctx_out->if_mgr, -+ lbinding->iface->name, -+ &lbinding->iface->header_.uuid); -+ } - -- if (lbinding) { -- /* Clear the iface of the local binding. */ -- lbinding->iface = NULL; -- } -+ } else if (b_lport && b_lport->type == LP_LOCALPORT) { -+ /* lbinding is associated with a localport. Remove it from the -+ * related lports. */ -+ remove_related_lport(b_lport->pb, b_ctx_out); -+ } - -- /* Check if the lbinding has children of type PB_CONTAINER. -- * If so, don't delete the local_binding. */ -- if (lbinding && !is_lbinding_container_parent(lbinding)) { -- local_binding_delete(lbinding, local_bindings, binding_lports, -- b_ctx_out->if_mgr); -+ /* Check if the lbinding has children of type PB_CONTAINER. -+ * If so, don't delete the local_binding. */ -+ if (!is_lbinding_container_parent(lbinding)) { -+ local_binding_delete(lbinding, local_bindings, binding_lports, -+ b_ctx_out->if_mgr); -+ } else { -+ /* Clear the iface of the local binding. */ -+ lbinding->iface = NULL; -+ } - } - - remove_local_lports(iface_id, b_ctx_out); -@@ -2938,7 +2971,7 @@ handle_updated_port(struct binding_ctx_in *b_ctx_in, - break; - - case LP_LOCALNET: { -- consider_localnet_lport(pb, b_ctx_in, b_ctx_out); -+ consider_localnet_lport(pb, b_ctx_out); - - struct shash bridge_mappings = - SHASH_INITIALIZER(&bridge_mappings); -@@ -3026,9 +3059,7 @@ binding_handle_port_binding_changes(struct binding_ctx_in *b_ctx_in, - shash_add(&deleted_other_pbs, pb->logical_port, pb); - } - -- remove_stale_qos_entry(b_ctx_in->ovs_idl_txn, pb, -- b_ctx_in->ovsrec_port_by_qos, -- b_ctx_in->qos_table, b_ctx_out->qos_map); -+ add_or_del_qos_port(pb->logical_port, false); - } - - struct shash_node *node; -@@ -3140,7 +3171,7 @@ delete_done: - b_ctx_in->sbrec_port_binding_by_datapath) { - enum en_lport_type lport_type = get_lport_type(pb); - if (lport_type == LP_LOCALNET) { -- consider_localnet_lport(pb, b_ctx_in, b_ctx_out); -+ consider_localnet_lport(pb, b_ctx_out); - update_ld_localnet_port(pb, &bridge_mappings, - b_ctx_out->local_datapaths); - } else if (lport_type == LP_EXTERNAL) { -@@ -3207,7 +3238,7 @@ local_binding_delete(struct local_binding *lbinding, - struct if_status_mgr *if_mgr) - { - shash_find_and_delete(local_bindings, lbinding->name); -- if_status_mgr_delete_iface(if_mgr, lbinding->name); -+ if_status_mgr_delete_iface(if_mgr, lbinding->name, lbinding->iface); - local_binding_destroy(lbinding, binding_lports); - } - -@@ -3424,6 +3455,80 @@ port_binding_set_down(const struct sbrec_chassis *chassis_rec, - } - } - -+void -+port_binding_set_up(const struct sbrec_chassis *chassis_rec, -+ const struct sbrec_port_binding_table *pb_table, -+ const char *iface_id, -+ const struct uuid *pb_uuid) -+{ -+ const struct sbrec_port_binding *pb = -+ sbrec_port_binding_table_get_for_uuid(pb_table, pb_uuid); -+ if (!pb) { -+ VLOG_DBG("port_binding already deleted for %s", iface_id); -+ return; -+ } -+ if (pb->n_up && !pb->up[0]) { -+ bool up = true; -+ sbrec_port_binding_set_up(pb, &up, 1); -+ VLOG_INFO("Setting lport %s up in Southbound", pb->logical_port); -+ set_pb_chassis_in_sbrec(pb, chassis_rec, true); -+ } -+} -+ -+void -+port_binding_set_pb(const struct sbrec_chassis *chassis_rec, -+ const struct sbrec_port_binding_table *pb_table, -+ const char *iface_id, -+ const struct uuid *pb_uuid, -+ enum can_bind bind_type) -+{ -+ const struct sbrec_port_binding *pb = -+ sbrec_port_binding_table_get_for_uuid(pb_table, pb_uuid); -+ if (!pb) { -+ VLOG_DBG("port_binding already deleted for %s", iface_id); -+ return; -+ } -+ if (bind_type == CAN_BIND_AS_MAIN) { -+ set_pb_chassis_in_sbrec(pb, chassis_rec, true); -+ } else if (bind_type == CAN_BIND_AS_ADDITIONAL) { -+ set_pb_additional_chassis_in_sbrec(pb, chassis_rec, true); -+ } -+} -+ -+bool -+port_binding_pb_chassis_is_set( -+ const struct sbrec_chassis *chassis_rec, -+ const struct sbrec_port_binding_table *pb_table, -+ const struct uuid *pb_uuid) -+{ -+ const struct sbrec_port_binding *pb = -+ sbrec_port_binding_table_get_for_uuid(pb_table, pb_uuid); -+ -+ if (pb && ((pb->chassis == chassis_rec) || -+ is_additional_chassis(pb, chassis_rec))) { -+ return true; -+ } -+ return false; -+} -+ -+bool -+port_binding_is_up(const struct sbrec_chassis *chassis_rec, -+ const struct sbrec_port_binding_table *pb_table, -+ const struct uuid *pb_uuid) -+{ -+ const struct sbrec_port_binding *pb = -+ sbrec_port_binding_table_get_for_uuid(pb_table, pb_uuid); -+ -+ if (!pb || pb->chassis != chassis_rec) { -+ return false; -+ } -+ -+ if (pb->n_up && !pb->up[0]) { -+ return false; -+ } -+ return true; -+} -+ - static void - binding_lport_set_up(struct binding_lport *b_lport, bool sb_readonly) - { -@@ -3614,5 +3719,6 @@ void - binding_destroy(void) - { - shash_destroy_free_data(&_claimed_ports); -+ shash_destroy_free_data(&_qos_ports); - sset_clear(&_postponed_ports); - } -diff --git a/controller/binding.h b/controller/binding.h -index 24bc84079..75e7a2679 100644 ---- a/controller/binding.h -+++ b/controller/binding.h -@@ -108,6 +108,9 @@ struct binding_ctx_out { - struct if_status_mgr *if_mgr; - - struct sset *postponed_ports; -+ -+ bool localnet_learn_fdb; -+ bool localnet_learn_fdb_changed; - }; - - /* Local bindings. binding.c module binds the logical port (represented by -@@ -217,6 +220,18 @@ void port_binding_set_down(const struct sbrec_chassis *chassis_rec, - const struct sbrec_port_binding_table *pb_table, - const char *iface_id, - const struct uuid *pb_uuid); -+void port_binding_set_up(const struct sbrec_chassis *chassis_rec, -+ const struct sbrec_port_binding_table *, -+ const char *iface_id, -+ const struct uuid *pb_uuid); -+void port_binding_set_pb(const struct sbrec_chassis *chassis_rec, -+ const struct sbrec_port_binding_table *, -+ const char *iface_id, -+ const struct uuid *pb_uuid, -+ enum can_bind bind_type); -+bool port_binding_pb_chassis_is_set(const struct sbrec_chassis *chassis_rec, -+ const struct sbrec_port_binding_table *, -+ const struct uuid *pb_uuid); - - /* This structure represents a logical port (or port binding) - * which is associated with 'struct local_binding'. -@@ -250,4 +265,20 @@ void binding_destroy(void); - - void destroy_qos_map(struct hmap *); - -+void update_qos(struct ovsdb_idl_index * sbrec_port_binding_by_name, -+ struct ovsdb_idl_txn *ovs_idl_txn, -+ struct ovsdb_idl_index *ovsrec_port_by_qos, -+ const struct ovsrec_qos_table *qos_table, -+ struct hmap *qos_map, -+ const struct ovsrec_open_vswitch_table *ovs_table, -+ const struct ovsrec_bridge_table *bridge_table); -+ -+bool lport_maybe_postpone(const char *port_name, long long int now, -+ struct sset *postponed_ports); -+ -+void claimed_lport_set_up(const struct sbrec_port_binding *pb, -+ const struct sbrec_port_binding *parent_pb); -+bool port_binding_is_up(const struct sbrec_chassis *chassis_rec, -+ const struct sbrec_port_binding_table *, -+ const struct uuid *pb_uuid); - #endif /* controller/binding.h */ -diff --git a/controller/chassis.c b/controller/chassis.c -index 031bd4463..ba2e57238 100644 ---- a/controller/chassis.c -+++ b/controller/chassis.c -@@ -369,6 +369,8 @@ chassis_build_other_config(const struct ovs_chassis_cfg *ovs_cfg, - smap_replace(config, OVN_FEATURE_MAC_BINDING_TIMESTAMP, "true"); - smap_replace(config, OVN_FEATURE_CT_LB_RELATED, "true"); - smap_replace(config, OVN_FEATURE_FDB_TIMESTAMP, "true"); -+ smap_replace(config, OVN_FEATURE_LS_DPG_COLUMN, "true"); -+ smap_replace(config, OVN_FEATURE_CT_COMMIT_NAT_V2, "true"); - } - - /* -@@ -502,6 +504,18 @@ chassis_other_config_changed(const struct ovs_chassis_cfg *ovs_cfg, - return true; - } - -+ if (!smap_get_bool(&chassis_rec->other_config, -+ OVN_FEATURE_LS_DPG_COLUMN, -+ false)) { -+ return true; -+ } -+ -+ if (!smap_get_bool(&chassis_rec->other_config, -+ OVN_FEATURE_CT_COMMIT_NAT_V2, -+ false)) { -+ return true; -+ } -+ - return false; - } - -@@ -632,6 +646,8 @@ update_supported_sset(struct sset *supported) - sset_add(supported, OVN_FEATURE_MAC_BINDING_TIMESTAMP); - sset_add(supported, OVN_FEATURE_CT_LB_RELATED); - sset_add(supported, OVN_FEATURE_FDB_TIMESTAMP); -+ sset_add(supported, OVN_FEATURE_LS_DPG_COLUMN); -+ sset_add(supported, OVN_FEATURE_CT_COMMIT_NAT_V2); - } - - static void -diff --git a/controller/if-status.c b/controller/if-status.c -index 6c5afc866..6e8aa1f7e 100644 ---- a/controller/if-status.c -+++ b/controller/if-status.c -@@ -177,7 +177,9 @@ static const char *if_state_names[] = { - - struct ovs_iface { - char *id; /* Extracted from OVS external_ids.iface_id. */ -+ char *name; /* OVS iface name. */ - struct uuid pb_uuid; /* Port_binding uuid */ -+ struct uuid parent_pb_uuid; /* Parent port_binding uuid */ - enum if_state state; /* State of the interface in the state machine. */ - uint32_t install_seqno; /* Seqno at which this interface is expected to - * be fully programmed in OVS. Only used in state -@@ -185,6 +187,7 @@ struct ovs_iface { - */ - uint16_t mtu; /* Extracted from OVS interface.mtu field. */ - enum can_bind bind_type;/* CAN_BIND_AS_MAIN or CAN_BIND_AS_ADDITIONAL */ -+ bool is_vif; /* Vifs, container or virtual ports */ - }; - - static uint64_t ifaces_usage; -@@ -224,6 +227,7 @@ static void if_status_mgr_update_bindings( - struct if_status_mgr *mgr, struct local_binding_data *binding_data, - const struct sbrec_chassis *, - const struct ovsrec_interface_table *iface_table, -+ const struct sbrec_port_binding_table *pb_table, - bool sb_readonly, bool ovs_readonly); - - static void ovn_uninstall_hash_account_mem(const char *name, bool erase); -@@ -273,12 +277,23 @@ if_status_mgr_destroy(struct if_status_mgr *mgr) - free(mgr); - } - -+/* is_vif controls whether we wait for flows to be updated -+ * before setting the interface up. It is true for VIF, CONTAINER -+ * and VIRTUAL ports. -+ * Non-VIF ports are reported up as soon as they are claimed -+ * to maintain compatibility with older versions. -+ * See aae25e6 binding: Correctly set Port_Binding.up for container/virtual -+ * ports. -+ */ -+ - void - if_status_mgr_claim_iface(struct if_status_mgr *mgr, - const struct sbrec_port_binding *pb, - const struct sbrec_chassis *chassis_rec, - const struct ovsrec_interface *iface_rec, -- bool sb_readonly, enum can_bind bind_type) -+ bool sb_readonly, enum can_bind bind_type, -+ bool is_vif, -+ const struct sbrec_port_binding *parent_pb) - { - const char *iface_id = pb->logical_port; - struct ovs_iface *iface = shash_find_data(&mgr->ifaces, iface_id); -@@ -287,8 +302,13 @@ if_status_mgr_claim_iface(struct if_status_mgr *mgr, - iface = ovs_iface_create(mgr, iface_id, iface_rec, OIF_CLAIMED); - } - iface->bind_type = bind_type; -+ iface->is_vif = is_vif; - - memcpy(&iface->pb_uuid, &pb->header_.uuid, sizeof(iface->pb_uuid)); -+ if (parent_pb) { -+ memcpy(&iface->parent_pb_uuid, &parent_pb->header_.uuid, -+ sizeof(iface->pb_uuid)); -+ } - if (!sb_readonly) { - if (bind_type == CAN_BIND_AS_MAIN) { - set_pb_chassis_in_sbrec(pb, chassis_rec, true); -@@ -357,7 +377,8 @@ if_status_mgr_release_iface(struct if_status_mgr *mgr, const char *iface_id) - } - - void --if_status_mgr_delete_iface(struct if_status_mgr *mgr, const char *iface_id) -+if_status_mgr_delete_iface(struct if_status_mgr *mgr, const char *iface_id, -+ const struct ovsrec_interface *iface_rec) - { - struct ovs_iface *iface = shash_find_data(&mgr->ifaces, iface_id); - -@@ -365,6 +386,12 @@ if_status_mgr_delete_iface(struct if_status_mgr *mgr, const char *iface_id) - return; - } - -+ if (iface_rec && strcmp(iface->name, iface_rec->name)) { -+ VLOG_DBG("Interface %s not deleted as port %s bound to %s", -+ iface_rec->name, iface_id, iface->name); -+ return; -+ } -+ - switch (iface->state) { - case OIF_CLAIMED: - case OIF_INSTALL_FLOWS: -@@ -394,6 +421,7 @@ if_status_handle_claims(struct if_status_mgr *mgr, - struct local_binding_data *binding_data, - const struct sbrec_chassis *chassis_rec, - struct hmap *tracked_datapath, -+ const struct sbrec_port_binding_table *pb_table, - bool sb_readonly) - { - if (!binding_data || sb_readonly) { -@@ -406,9 +434,15 @@ if_status_handle_claims(struct if_status_mgr *mgr, - bool rc = false; - HMAPX_FOR_EACH (node, &mgr->ifaces_per_state[OIF_CLAIMED]) { - struct ovs_iface *iface = node->data; -- VLOG_INFO("if_status_handle_claims for %s", iface->id); -- local_binding_set_pb(bindings, iface->id, chassis_rec, -- tracked_datapath, true, iface->bind_type); -+ VLOG_DBG("if_status_handle_claims for %s, is_vif = %d", iface->id, -+ iface->is_vif); -+ if (iface->is_vif) { -+ local_binding_set_pb(bindings, iface->id, chassis_rec, -+ tracked_datapath, true, iface->bind_type); -+ } else { -+ port_binding_set_pb(chassis_rec, pb_table, iface->id, -+ &iface->pb_uuid, iface->bind_type); -+ } - rc = true; - } - return rc; -@@ -470,18 +504,37 @@ if_status_mgr_update(struct if_status_mgr *mgr, - */ - HMAPX_FOR_EACH_SAFE (node, &mgr->ifaces_per_state[OIF_MARK_UP]) { - struct ovs_iface *iface = node->data; -- -- if (!local_bindings_pb_chassis_is_set(bindings, iface->id, -- chassis_rec)) { -- if (!sb_readonly) { -- local_binding_set_pb(bindings, iface->id, chassis_rec, -- NULL, true, iface->bind_type); -- } else { -- continue; -+ if (iface->is_vif) { -+ if (!local_bindings_pb_chassis_is_set(bindings, iface->id, -+ chassis_rec)) { -+ if (!sb_readonly) { -+ long long int now = time_msec(); -+ if (lport_maybe_postpone(iface->id, now, -+ get_postponed_ports())) { -+ continue; -+ } -+ local_binding_set_pb(bindings, iface->id, chassis_rec, -+ NULL, true, iface->bind_type); -+ } else { -+ continue; -+ } -+ } -+ if (local_binding_is_up(bindings, iface->id, chassis_rec)) { -+ ovs_iface_set_state(mgr, iface, OIF_INSTALLED); -+ } -+ } else { -+ if (!port_binding_pb_chassis_is_set(chassis_rec, pb_table, -+ &iface->pb_uuid)) { -+ if (!sb_readonly) { -+ port_binding_set_pb(chassis_rec, pb_table, iface->id, -+ &iface->pb_uuid, iface->bind_type); -+ } else { -+ continue; -+ } -+ } -+ if (port_binding_is_up(chassis_rec, pb_table, &iface->pb_uuid)) { -+ ovs_iface_set_state(mgr, iface, OIF_INSTALLED); - } -- } -- if (local_binding_is_up(bindings, iface->id, chassis_rec)) { -- ovs_iface_set_state(mgr, iface, OIF_INSTALLED); - } - } - -@@ -510,9 +563,13 @@ if_status_mgr_update(struct if_status_mgr *mgr, - if (!sb_readonly) { - HMAPX_FOR_EACH_SAFE (node, &mgr->ifaces_per_state[OIF_INSTALL_FLOWS]) { - struct ovs_iface *iface = node->data; -- - if (!local_bindings_pb_chassis_is_set(bindings, iface->id, - chassis_rec)) { -+ long long int now = time_msec(); -+ if (lport_maybe_postpone(iface->id, now, -+ get_postponed_ports())) { -+ continue; -+ } - local_binding_set_pb(bindings, iface->id, chassis_rec, - NULL, true, iface->bind_type); - } -@@ -528,9 +585,13 @@ if_status_mgr_update(struct if_status_mgr *mgr, - /* No need to to update pb->chassis as already done - * in if_status_handle_claims or if_status_mgr_claim_iface - */ -- ovs_iface_set_state(mgr, iface, OIF_INSTALL_FLOWS); -- iface->install_seqno = mgr->iface_seqno + 1; -- new_ifaces = true; -+ if (iface->is_vif) { -+ ovs_iface_set_state(mgr, iface, OIF_INSTALL_FLOWS); -+ iface->install_seqno = mgr->iface_seqno + 1; -+ new_ifaces = true; -+ } else { -+ ovs_iface_set_state(mgr, iface, OIF_MARK_UP); -+ } - } - } else { - HMAPX_FOR_EACH_SAFE (node, &mgr->ifaces_per_state[OIF_CLAIMED]) { -@@ -587,6 +648,7 @@ if_status_mgr_run(struct if_status_mgr *mgr, - struct local_binding_data *binding_data, - const struct sbrec_chassis *chassis_rec, - const struct ovsrec_interface_table *iface_table, -+ const struct sbrec_port_binding_table *pb_table, - bool sb_readonly, bool ovs_readonly) - { - struct ofctrl_acked_seqnos *acked_seqnos = -@@ -622,15 +684,18 @@ if_status_mgr_run(struct if_status_mgr *mgr, - - /* Update binding states. */ - if_status_mgr_update_bindings(mgr, binding_data, chassis_rec, -- iface_table, -+ iface_table, pb_table, - sb_readonly, ovs_readonly); - } - - static void --ovs_iface_account_mem(const char *iface_id, bool erase) -+ovs_iface_account_mem(const char *iface_id, char *iface_name, bool erase) - { - uint32_t size = (strlen(iface_id) + sizeof(struct ovs_iface) + - sizeof(struct shash_node)); -+ if (iface_name) { -+ size += strlen(iface_name); -+ } - if (erase) { - ifaces_usage -= size; - } else { -@@ -682,12 +747,18 @@ ovs_iface_create(struct if_status_mgr *mgr, const char *iface_id, - { - struct ovs_iface *iface = xzalloc(sizeof *iface); - -- VLOG_DBG("Interface %s create.", iface_id); -+ VLOG_DBG("Interface %s create for iface %s.", iface_id, -+ iface_rec ? iface_rec->name : ""); - iface->id = xstrdup(iface_id); - shash_add_nocopy(&mgr->ifaces, iface->id, iface); - ovs_iface_set_state(mgr, iface, state); -- ovs_iface_account_mem(iface_id, false); -- if_status_mgr_iface_update(mgr, iface_rec); -+ if (iface_rec) { -+ ovs_iface_account_mem(iface_id, iface_rec->name, false); -+ if_status_mgr_iface_update(mgr, iface_rec); -+ iface->name = xstrdup(iface_rec->name); -+ } else { -+ ovs_iface_account_mem(iface_id, NULL, false); -+ } - return iface; - } - -@@ -711,7 +782,8 @@ ovs_iface_destroy(struct if_status_mgr *mgr, struct ovs_iface *iface) - if (node) { - shash_steal(&mgr->ifaces, node); - } -- ovs_iface_account_mem(iface->id, true); -+ ovs_iface_account_mem(iface->id, iface->name, true); -+ free(iface->name); - free(iface->id); - free(iface); - } -@@ -752,6 +824,7 @@ if_status_mgr_update_bindings(struct if_status_mgr *mgr, - struct local_binding_data *binding_data, - const struct sbrec_chassis *chassis_rec, - const struct ovsrec_interface_table *iface_table, -+ const struct sbrec_port_binding_table *pb_table, - bool sb_readonly, bool ovs_readonly) - { - if (!binding_data) { -@@ -788,9 +861,20 @@ if_status_mgr_update_bindings(struct if_status_mgr *mgr, - char *ts_now_str = xasprintf("%lld", time_wall_msec()); - HMAPX_FOR_EACH (node, &mgr->ifaces_per_state[OIF_MARK_UP]) { - struct ovs_iface *iface = node->data; -- -- local_binding_set_up(bindings, iface->id, chassis_rec, ts_now_str, -- sb_readonly, ovs_readonly); -+ if (iface->is_vif) { -+ local_binding_set_up(bindings, iface->id, chassis_rec, ts_now_str, -+ sb_readonly, ovs_readonly); -+ } else if (!sb_readonly) { -+ const struct sbrec_port_binding *pb = -+ sbrec_port_binding_table_get_for_uuid(pb_table, -+ &iface->pb_uuid); -+ if (pb) { -+ const struct sbrec_port_binding *parent_pb = -+ sbrec_port_binding_table_get_for_uuid(pb_table, -+ &iface->parent_pb_uuid); -+ claimed_lport_set_up(pb, parent_pb); -+ } -+ } - } - free(ts_now_str); - -diff --git a/controller/if-status.h b/controller/if-status.h -index 9714f6d8d..4ae5ad481 100644 ---- a/controller/if-status.h -+++ b/controller/if-status.h -@@ -32,9 +32,12 @@ void if_status_mgr_claim_iface(struct if_status_mgr *, - const struct sbrec_port_binding *pb, - const struct sbrec_chassis *chassis_rec, - const struct ovsrec_interface *iface_rec, -- bool sb_readonly, enum can_bind bind_type); -+ bool sb_readonly, enum can_bind bind_type, -+ bool notify_up, -+ const struct sbrec_port_binding *parent_pb); - void if_status_mgr_release_iface(struct if_status_mgr *, const char *iface_id); --void if_status_mgr_delete_iface(struct if_status_mgr *, const char *iface_id); -+void if_status_mgr_delete_iface(struct if_status_mgr *, const char *iface_id, -+ const struct ovsrec_interface *iface_rec); - - void if_status_mgr_update(struct if_status_mgr *, struct local_binding_data *, - const struct sbrec_chassis *chassis, -@@ -45,6 +48,7 @@ void if_status_mgr_update(struct if_status_mgr *, struct local_binding_data *, - void if_status_mgr_run(struct if_status_mgr *mgr, struct local_binding_data *, - const struct sbrec_chassis *, - const struct ovsrec_interface_table *iface_table, -+ const struct sbrec_port_binding_table *pb_table, - bool sb_readonly, bool ovs_readonly); - void if_status_mgr_get_memory_usage(struct if_status_mgr *mgr, - struct simap *usage); -@@ -54,6 +58,7 @@ bool if_status_handle_claims(struct if_status_mgr *mgr, - struct local_binding_data *binding_data, - const struct sbrec_chassis *chassis_rec, - struct hmap *tracked_datapath, -+ const struct sbrec_port_binding_table *pb_table, - bool sb_readonly); - void if_status_mgr_remove_ovn_installed(struct if_status_mgr *mgr, - const char *name, -diff --git a/controller/lflow.c b/controller/lflow.c -index f70080e8e..b0cf4253c 100644 ---- a/controller/lflow.c -+++ b/controller/lflow.c -@@ -1017,6 +1017,7 @@ convert_match_to_expr(const struct sbrec_logical_flow *lflow, - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); - VLOG_WARN_RL(&rl, "error parsing match \"%s\": %s", - lflow->match, error); -+ expr_destroy(e); - free(error); - return NULL; - } -@@ -1892,6 +1893,7 @@ add_lb_ct_snat_hairpin_vip_flow(const struct ovn_controller_lb *lb, - local_datapaths, &match, - &ofpacts, flow_table); - } -+ /* datapath_group column is deprecated. */ - if (lb->slb->datapath_group) { - for (size_t i = 0; i < lb->slb->datapath_group->n_datapaths; i++) { - add_lb_ct_snat_hairpin_for_dp( -@@ -1900,6 +1902,15 @@ add_lb_ct_snat_hairpin_vip_flow(const struct ovn_controller_lb *lb, - local_datapaths, &match, &ofpacts, flow_table); - } - } -+ if (lb->slb->ls_datapath_group) { -+ for (size_t i = 0; -+ i < lb->slb->ls_datapath_group->n_datapaths; i++) { -+ add_lb_ct_snat_hairpin_for_dp( -+ lb, !!lb_vip->vip_port, -+ lb->slb->ls_datapath_group->datapaths[i], -+ local_datapaths, &match, &ofpacts, flow_table); -+ } -+ } - } - - ofpbuf_uninit(&ofpacts); -@@ -2055,11 +2066,17 @@ lflow_handle_changed_static_mac_bindings( - static void - consider_fdb_flows(const struct sbrec_fdb *fdb, - const struct hmap *local_datapaths, -- struct ovn_desired_flow_table *flow_table) -+ struct ovn_desired_flow_table *flow_table, -+ struct ovsdb_idl_index *sbrec_port_binding_by_key, -+ bool localnet_learn_fdb) - { -- if (!get_local_datapath(local_datapaths, fdb->dp_key)) { -+ struct local_datapath *ld = get_local_datapath(local_datapaths, -+ fdb->dp_key); -+ if (!ld) { - return; - } -+ const struct sbrec_port_binding *pb = lport_lookup_by_key_with_dp( -+ sbrec_port_binding_by_key, ld->datapath, fdb->port_key); - - struct eth_addr mac; - if (!eth_addr_from_string(fdb->mac, &mac)) { -@@ -2081,6 +2098,7 @@ consider_fdb_flows(const struct sbrec_fdb *fdb, - ofpbuf_clear(&ofpacts); - - uint8_t value = 1; -+ uint8_t is_vif = pb ? !strcmp(pb->type, "") : 0; - put_load(&value, sizeof value, MFF_LOG_FLAGS, - MLF_LOOKUP_FDB_BIT, 1, &ofpacts); - -@@ -2091,6 +2109,18 @@ consider_fdb_flows(const struct sbrec_fdb *fdb, - ofctrl_add_flow(flow_table, OFTABLE_LOOKUP_FDB, 100, - fdb->header_.uuid.parts[0], &lookup_match, &ofpacts, - &fdb->header_.uuid); -+ -+ if (is_vif && localnet_learn_fdb) { -+ struct match lookup_match_vif = MATCH_CATCHALL_INITIALIZER; -+ match_set_metadata(&lookup_match_vif, htonll(fdb->dp_key)); -+ match_set_dl_src(&lookup_match_vif, mac); -+ match_set_reg_masked(&lookup_match_vif, MFF_LOG_FLAGS - MFF_REG0, -+ MLF_LOCALNET, MLF_LOCALNET); -+ -+ ofctrl_add_flow(flow_table, OFTABLE_LOOKUP_FDB, 100, -+ fdb->header_.uuid.parts[0], &lookup_match_vif, -+ &ofpacts, &fdb->header_.uuid); -+ } - ofpbuf_uninit(&ofpacts); - } - -@@ -2099,11 +2129,14 @@ consider_fdb_flows(const struct sbrec_fdb *fdb, - static void - add_fdb_flows(const struct sbrec_fdb_table *fdb_table, - const struct hmap *local_datapaths, -- struct ovn_desired_flow_table *flow_table) -+ struct ovn_desired_flow_table *flow_table, -+ struct ovsdb_idl_index *sbrec_port_binding_by_key, -+ bool localnet_learn_fdb) - { - const struct sbrec_fdb *fdb; - SBREC_FDB_TABLE_FOR_EACH (fdb, fdb_table) { -- consider_fdb_flows(fdb, local_datapaths, flow_table); -+ consider_fdb_flows(fdb, local_datapaths, flow_table, -+ sbrec_port_binding_by_key, localnet_learn_fdb); - } - } - -@@ -2126,7 +2159,9 @@ lflow_run(struct lflow_ctx_in *l_ctx_in, struct lflow_ctx_out *l_ctx_out) - l_ctx_in->lb_hairpin_use_ct_mark, - l_ctx_out->flow_table); - add_fdb_flows(l_ctx_in->fdb_table, l_ctx_in->local_datapaths, -- l_ctx_out->flow_table); -+ l_ctx_out->flow_table, -+ l_ctx_in->sbrec_port_binding_by_key, -+ l_ctx_in->localnet_learn_fdb); - add_port_sec_flows(l_ctx_in->binding_lports, l_ctx_in->chassis, - l_ctx_out->flow_table); - } -@@ -2216,7 +2251,9 @@ lflow_add_flows_for_datapath(const struct sbrec_datapath_binding *dp, - SBREC_FDB_FOR_EACH_EQUAL (fdb_row, fdb_index_row, - l_ctx_in->sbrec_fdb_by_dp_key) { - consider_fdb_flows(fdb_row, l_ctx_in->local_datapaths, -- l_ctx_out->flow_table); -+ l_ctx_out->flow_table, -+ l_ctx_in->sbrec_port_binding_by_key, -+ l_ctx_in->localnet_learn_fdb); - } - sbrec_fdb_index_destroy_row(fdb_index_row); - -@@ -2280,6 +2317,15 @@ lflow_handle_flows_for_lport(const struct sbrec_port_binding *pb, - pb->logical_port)) { - consider_port_sec_flows(pb, l_ctx_out->flow_table); - } -+ if (l_ctx_in->localnet_learn_fdb_changed && l_ctx_in->localnet_learn_fdb) { -+ const struct sbrec_fdb *fdb; -+ SBREC_FDB_TABLE_FOR_EACH (fdb, l_ctx_in->fdb_table) { -+ consider_fdb_flows(fdb, l_ctx_in->local_datapaths, -+ l_ctx_out->flow_table, -+ l_ctx_in->sbrec_port_binding_by_key, -+ l_ctx_in->localnet_learn_fdb); -+ } -+ } - return true; - } - -@@ -2409,7 +2455,9 @@ lflow_handle_changed_fdbs(struct lflow_ctx_in *l_ctx_in, - VLOG_DBG("Add fdb flows for fdb "UUID_FMT, - UUID_ARGS(&fdb->header_.uuid)); - consider_fdb_flows(fdb, l_ctx_in->local_datapaths, -- l_ctx_out->flow_table); -+ l_ctx_out->flow_table, -+ l_ctx_in->sbrec_port_binding_by_key, -+ l_ctx_in->localnet_learn_fdb); - } - - return true; -diff --git a/controller/lflow.h b/controller/lflow.h -index 5da4385e4..9b7ffa19c 100644 ---- a/controller/lflow.h -+++ b/controller/lflow.h -@@ -100,6 +100,7 @@ struct lflow_ctx_in { - struct ovsdb_idl_index *sbrec_logical_flow_by_logical_datapath; - struct ovsdb_idl_index *sbrec_logical_flow_by_logical_dp_group; - struct ovsdb_idl_index *sbrec_port_binding_by_name; -+ struct ovsdb_idl_index *sbrec_port_binding_by_key; - struct ovsdb_idl_index *sbrec_fdb_by_dp_key; - struct ovsdb_idl_index *sbrec_mac_binding_by_datapath; - struct ovsdb_idl_index *sbrec_static_mac_binding_by_datapath; -@@ -127,6 +128,8 @@ struct lflow_ctx_in { - const struct flow_collector_ids *collector_ids; - const struct hmap *local_lbs; - bool lb_hairpin_use_ct_mark; -+ bool localnet_learn_fdb; -+ bool localnet_learn_fdb_changed; - }; - - struct lflow_ctx_out { -diff --git a/controller/local_data.c b/controller/local_data.c -index cf0b21bb1..ab18386c7 100644 ---- a/controller/local_data.c -+++ b/controller/local_data.c -@@ -56,6 +56,20 @@ static bool datapath_is_transit_switch(const struct sbrec_datapath_binding *); - - static uint64_t local_datapath_usage; - -+/* To be used when hmap_node.hash might be wrong e.g. tunnel_key got updated */ -+struct local_datapath * -+get_local_datapath_no_hash(const struct hmap *local_datapaths, -+ uint32_t tunnel_key) -+{ -+ struct local_datapath *ld; -+ HMAP_FOR_EACH (ld, hmap_node, local_datapaths) { -+ if (ld->datapath->tunnel_key == tunnel_key) { -+ return ld; -+ } -+ } -+ return NULL; -+} -+ - struct local_datapath * - get_local_datapath(const struct hmap *local_datapaths, uint32_t tunnel_key) - { -@@ -661,8 +675,24 @@ lb_is_local(const struct sbrec_load_balancer *sbrec_lb, - } - } - -+ /* datapath_group column is deprecated. */ - struct sbrec_logical_dp_group *dp_group = sbrec_lb->datapath_group; -+ for (size_t i = 0; dp_group && i < dp_group->n_datapaths; i++) { -+ if (get_local_datapath(local_datapaths, -+ dp_group->datapaths[i]->tunnel_key)) { -+ return true; -+ } -+ } -+ -+ dp_group = sbrec_lb->ls_datapath_group; -+ for (size_t i = 0; dp_group && i < dp_group->n_datapaths; i++) { -+ if (get_local_datapath(local_datapaths, -+ dp_group->datapaths[i]->tunnel_key)) { -+ return true; -+ } -+ } - -+ dp_group = sbrec_lb->lr_datapath_group; - for (size_t i = 0; dp_group && i < dp_group->n_datapaths; i++) { - if (get_local_datapath(local_datapaths, - dp_group->datapaths[i]->tunnel_key)) { -diff --git a/controller/local_data.h b/controller/local_data.h -index f6d8f725f..2a1a3c0f9 100644 ---- a/controller/local_data.h -+++ b/controller/local_data.h -@@ -69,6 +69,10 @@ struct local_datapath *local_datapath_alloc( - const struct sbrec_datapath_binding *); - struct local_datapath *get_local_datapath(const struct hmap *, - uint32_t tunnel_key); -+struct local_datapath *get_local_datapath_no_hash( -+ const struct hmap *local_datapaths, -+ uint32_t tunnel_key); -+ - bool - need_add_peer_to_local( - struct ovsdb_idl_index *sbrec_port_binding_by_name, -diff --git a/controller/lport.c b/controller/lport.c -index add7e91aa..b3721024b 100644 ---- a/controller/lport.c -+++ b/controller/lport.c -@@ -44,13 +44,10 @@ lport_lookup_by_name(struct ovsdb_idl_index *sbrec_port_binding_by_name, - } - - const struct sbrec_port_binding * --lport_lookup_by_key(struct ovsdb_idl_index *sbrec_datapath_binding_by_key, -- struct ovsdb_idl_index *sbrec_port_binding_by_key, -- uint64_t dp_key, uint64_t port_key) -+lport_lookup_by_key_with_dp(struct ovsdb_idl_index *sbrec_port_binding_by_key, -+ const struct sbrec_datapath_binding *db, -+ uint64_t port_key) - { -- /* Lookup datapath corresponding to dp_key. */ -- const struct sbrec_datapath_binding *db = datapath_lookup_by_key( -- sbrec_datapath_binding_by_key, dp_key); - if (!db) { - return NULL; - } -@@ -69,6 +66,19 @@ lport_lookup_by_key(struct ovsdb_idl_index *sbrec_datapath_binding_by_key, - return retval; - } - -+const struct sbrec_port_binding * -+lport_lookup_by_key(struct ovsdb_idl_index *sbrec_datapath_binding_by_key, -+ struct ovsdb_idl_index *sbrec_port_binding_by_key, -+ uint64_t dp_key, uint64_t port_key) -+{ -+ /* Lookup datapath corresponding to dp_key. */ -+ const struct sbrec_datapath_binding *db = datapath_lookup_by_key( -+ sbrec_datapath_binding_by_key, dp_key); -+ -+ return lport_lookup_by_key_with_dp(sbrec_port_binding_by_key, db, -+ port_key); -+} -+ - bool - lport_is_chassis_resident(struct ovsdb_idl_index *sbrec_port_binding_by_name, - const struct sbrec_chassis *chassis, -diff --git a/controller/lport.h b/controller/lport.h -index 644c67255..2f72aef5e 100644 ---- a/controller/lport.h -+++ b/controller/lport.h -@@ -43,6 +43,10 @@ const struct sbrec_port_binding *lport_lookup_by_key( - struct ovsdb_idl_index *sbrec_port_binding_by_key, - uint64_t dp_key, uint64_t port_key); - -+const struct sbrec_port_binding *lport_lookup_by_key_with_dp( -+ struct ovsdb_idl_index *sbrec_port_binding_by_key, -+ const struct sbrec_datapath_binding *dp, uint64_t port_key); -+ - enum can_bind { - CANNOT_BIND = 0, - CAN_BIND_AS_MAIN, -diff --git a/controller/ofctrl.c b/controller/ofctrl.c -index a1676a788..1f06f4e48 100644 ---- a/controller/ofctrl.c -+++ b/controller/ofctrl.c -@@ -2259,18 +2259,29 @@ ofctrl_meter_bands_erase(struct ovn_extend_table_info *entry, - } - } - -+static const struct sbrec_meter * -+sb_meter_lookup_by_name(struct ovsdb_idl_index *sbrec_meter_by_name, -+ const char *name) -+{ -+ const struct sbrec_meter *sb_meter; -+ struct sbrec_meter *index_row; -+ -+ index_row = sbrec_meter_index_init_row(sbrec_meter_by_name); -+ sbrec_meter_index_set_name(index_row, name); -+ sb_meter = sbrec_meter_index_find(sbrec_meter_by_name, index_row); -+ sbrec_meter_index_destroy_row(index_row); -+ -+ return sb_meter; -+} -+ - static void - ofctrl_meter_bands_sync(struct ovn_extend_table_info *m_existing, -- const struct sbrec_meter_table *meter_table, -+ struct ovsdb_idl_index *sbrec_meter_by_name, - struct ovs_list *msgs) - { - const struct sbrec_meter *sb_meter; -- SBREC_METER_TABLE_FOR_EACH (sb_meter, meter_table) { -- if (!strcmp(m_existing->name, sb_meter->name)) { -- break; -- } -- } - -+ sb_meter = sb_meter_lookup_by_name(sbrec_meter_by_name, m_existing->name); - if (sb_meter) { - /* OFPMC13_ADD or OFPMC13_MODIFY */ - ofctrl_meter_bands_update(sb_meter, m_existing, msgs); -@@ -2282,16 +2293,12 @@ ofctrl_meter_bands_sync(struct ovn_extend_table_info *m_existing, - - static void - add_meter(struct ovn_extend_table_info *m_desired, -- const struct sbrec_meter_table *meter_table, -+ struct ovsdb_idl_index *sbrec_meter_by_name, - struct ovs_list *msgs) - { - const struct sbrec_meter *sb_meter; -- SBREC_METER_TABLE_FOR_EACH (sb_meter, meter_table) { -- if (!strcmp(m_desired->name, sb_meter->name)) { -- break; -- } -- } - -+ sb_meter = sb_meter_lookup_by_name(sbrec_meter_by_name, m_desired->name); - if (!sb_meter) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_ERR_RL(&rl, "could not find meter named \"%s\"", m_desired->name); -@@ -2658,7 +2665,7 @@ ofctrl_put(struct ovn_desired_flow_table *lflow_table, - struct ovn_desired_flow_table *pflow_table, - struct shash *pending_ct_zones, - struct hmap *pending_lb_tuples, -- const struct sbrec_meter_table *meter_table, -+ struct ovsdb_idl_index *sbrec_meter_by_name, - uint64_t req_cfg, - bool lflows_changed, - bool pflows_changed) -@@ -2735,10 +2742,10 @@ ofctrl_put(struct ovn_desired_flow_table *lflow_table, - * describes the meter itself. */ - add_meter_string(m_desired, &msgs); - } else { -- add_meter(m_desired, meter_table, &msgs); -+ add_meter(m_desired, sbrec_meter_by_name, &msgs); - } - } else { -- ofctrl_meter_bands_sync(m_existing, meter_table, &msgs); -+ ofctrl_meter_bands_sync(m_existing, sbrec_meter_by_name, &msgs); - } - } - -diff --git a/controller/ofctrl.h b/controller/ofctrl.h -index 105f9370b..bb7891440 100644 ---- a/controller/ofctrl.h -+++ b/controller/ofctrl.h -@@ -59,7 +59,7 @@ void ofctrl_put(struct ovn_desired_flow_table *lflow_table, - struct ovn_desired_flow_table *pflow_table, - struct shash *pending_ct_zones, - struct hmap *pending_lb_tuples, -- const struct sbrec_meter_table *, -+ struct ovsdb_idl_index *sbrec_meter_by_name, - uint64_t nb_cfg, - bool lflow_changed, - bool pflow_changed); -diff --git a/controller/ovn-controller.8.xml b/controller/ovn-controller.8.xml -index 7b4100592..0b9641045 100644 ---- a/controller/ovn-controller.8.xml -+++ b/controller/ovn-controller.8.xml -@@ -363,7 +363,10 @@ - The boolean flag indicates if ovn-controller when create - tunnel ports should set local_ip parameter. Can be - heplful to pin source outer IP for the tunnel when multiple interfaces -- are used on the host for overlay traffic. -+ are used on the host for overlay traffic. This is also useful when -+ running multiple ovn-controller instances on the same -+ chassis, in which case this setting will guarantee that their tunnel -+ ports have unique configuration and can exist in parallel. - -
external_ids:garp-max-timeout-sec
-
-@@ -398,9 +401,11 @@ - names on the same host using the same vswitchd instance. - This may be useful when running a hybrid setup with more than one CMS - managing ports on the host, or to use different datapath types on the -- same host. Note that this ability is highly experimental and has known -- limitations (for example, stateful ACLs are not supported). Use at your -- own risk. -+ same host. Make sure you also set -+ external_ids:ovn-set-local-ip when using such -+ configuration. Also note that this ability is highly experimental and -+ has known limitations (for example, stateful ACLs are not supported). -+ Use at your own risk. -

- -

-diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c -index b3e4e0da8..003490a06 100644 ---- a/controller/ovn-controller.c -+++ b/controller/ovn-controller.c -@@ -88,7 +88,6 @@ - - VLOG_DEFINE_THIS_MODULE(main); - --static unixctl_cb_func ovn_controller_exit; - static unixctl_cb_func ct_zone_list; - static unixctl_cb_func extend_table_list; - static unixctl_cb_func inject_pkt; -@@ -211,8 +210,8 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl, - { - /* Monitor Port_Bindings rows for local interfaces and local datapaths. - * -- * Monitor Logical_Flow, MAC_Binding, Multicast_Group, and DNS tables for -- * local datapaths. -+ * Monitor Logical_Flow, MAC_Binding, FDB, Multicast_Group, and DNS tables -+ * for local datapaths. - * - * Monitor Controller_Event rows for local chassis. - * -@@ -230,6 +229,7 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl, - struct ovsdb_idl_condition lf = OVSDB_IDL_CONDITION_INIT(&lf); - struct ovsdb_idl_condition ldpg = OVSDB_IDL_CONDITION_INIT(&ldpg); - struct ovsdb_idl_condition mb = OVSDB_IDL_CONDITION_INIT(&mb); -+ struct ovsdb_idl_condition fdb = OVSDB_IDL_CONDITION_INIT(&fdb); - struct ovsdb_idl_condition mg = OVSDB_IDL_CONDITION_INIT(&mg); - struct ovsdb_idl_condition dns = OVSDB_IDL_CONDITION_INIT(&dns); - struct ovsdb_idl_condition ce = OVSDB_IDL_CONDITION_INIT(&ce); -@@ -248,6 +248,7 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl, - ovsdb_idl_condition_add_clause_true(&pb); - ovsdb_idl_condition_add_clause_true(&lf); - ovsdb_idl_condition_add_clause_true(&mb); -+ ovsdb_idl_condition_add_clause_true(&fdb); - ovsdb_idl_condition_add_clause_true(&mg); - ovsdb_idl_condition_add_clause_true(&dns); - ovsdb_idl_condition_add_clause_true(&ce); -@@ -337,6 +338,8 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl, - sbrec_logical_flow_add_clause_logical_datapath(&lf, OVSDB_F_EQ, - uuid); - sbrec_mac_binding_add_clause_datapath(&mb, OVSDB_F_EQ, uuid); -+ sbrec_fdb_add_clause_dp_key(&fdb, OVSDB_F_EQ, -+ ld->datapath->tunnel_key); - sbrec_multicast_group_add_clause_datapath(&mg, OVSDB_F_EQ, uuid); - sbrec_dns_add_clause_datapaths(&dns, OVSDB_F_INCLUDES, &uuid, 1); - sbrec_ip_multicast_add_clause_datapath(&ip_mcast, OVSDB_F_EQ, -@@ -360,6 +363,7 @@ out:; - sb_table_set_req_mon_condition(ovnsb_idl, logical_flow, &lf), - sb_table_set_req_mon_condition(ovnsb_idl, logical_dp_group, &ldpg), - sb_table_set_req_mon_condition(ovnsb_idl, mac_binding, &mb), -+ sb_table_set_req_mon_condition(ovnsb_idl, fdb, &fdb), - sb_table_set_req_mon_condition(ovnsb_idl, multicast_group, &mg), - sb_table_set_req_mon_condition(ovnsb_idl, dns, &dns), - sb_table_set_req_mon_condition(ovnsb_idl, controller_event, &ce), -@@ -378,6 +382,7 @@ out:; - ovsdb_idl_condition_destroy(&lf); - ovsdb_idl_condition_destroy(&ldpg); - ovsdb_idl_condition_destroy(&mb); -+ ovsdb_idl_condition_destroy(&fdb); - ovsdb_idl_condition_destroy(&mg); - ovsdb_idl_condition_destroy(&dns); - ovsdb_idl_condition_destroy(&ce); -@@ -1499,6 +1504,8 @@ struct ed_type_runtime_data { - /* Tracked data. See below for more details and comments. */ - bool tracked; - bool local_lports_changed; -+ bool localnet_learn_fdb; -+ bool localnet_learn_fdb_changed; - struct hmap tracked_dp_bindings; - - struct shash local_active_ports_ipv6_pd; -@@ -1709,6 +1716,8 @@ init_binding_ctx(struct engine_node *node, - b_ctx_out->postponed_ports = rt_data->postponed_ports; - b_ctx_out->tracked_dp_bindings = NULL; - b_ctx_out->if_mgr = ctrl_ctx->if_mgr; -+ b_ctx_out->localnet_learn_fdb = rt_data->localnet_learn_fdb; -+ b_ctx_out->localnet_learn_fdb_changed = false; - } - - static void -@@ -1766,6 +1775,7 @@ en_runtime_data_run(struct engine_node *node, void *data) - } - - binding_run(&b_ctx_in, &b_ctx_out); -+ rt_data->localnet_learn_fdb = b_ctx_out.localnet_learn_fdb; - - engine_set_node_state(node, EN_UPDATED); - } -@@ -1815,6 +1825,8 @@ runtime_data_sb_ro_handler(struct engine_node *node, void *data) - engine_ovsdb_node_get_index( - engine_get_input("SB_chassis", node), - "name"); -+ const struct sbrec_port_binding_table *pb_table = -+ EN_OVSDB_GET(engine_get_input("SB_port_binding", node)); - - if (chassis_id) { - chassis = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id); -@@ -1829,7 +1841,7 @@ runtime_data_sb_ro_handler(struct engine_node *node, void *data) - &rt_data->lbinding_data, - chassis, - &rt_data->tracked_dp_bindings, -- sb_readonly)) { -+ pb_table, sb_readonly)) { - engine_set_node_state(node, EN_UPDATED); - rt_data->tracked = true; - } -@@ -1878,9 +1890,12 @@ runtime_data_sb_port_binding_handler(struct engine_node *node, void *data) - } - - rt_data->local_lports_changed = b_ctx_out.local_lports_changed; -+ rt_data->localnet_learn_fdb = b_ctx_out.localnet_learn_fdb; -+ rt_data->localnet_learn_fdb_changed = b_ctx_out.localnet_learn_fdb_changed; - if (b_ctx_out.related_lports_changed || - b_ctx_out.non_vif_ports_changed || - b_ctx_out.local_lports_changed || -+ b_ctx_out.localnet_learn_fdb_changed || - !hmap_is_empty(b_ctx_out.tracked_dp_bindings)) { - engine_set_node_state(node, EN_UPDATED); - } -@@ -1897,6 +1912,7 @@ runtime_data_sb_datapath_binding_handler(struct engine_node *node OVS_UNUSED, - engine_get_input("SB_datapath_binding", node)); - const struct sbrec_datapath_binding *dp; - struct ed_type_runtime_data *rt_data = data; -+ struct local_datapath *ld; - - SBREC_DATAPATH_BINDING_TABLE_FOR_EACH_TRACKED (dp, dp_table) { - if (sbrec_datapath_binding_is_deleted(dp)) { -@@ -1904,6 +1920,28 @@ runtime_data_sb_datapath_binding_handler(struct engine_node *node OVS_UNUSED, - dp->tunnel_key)) { - return false; - } -+ /* If the tunnel key got updated, get_local_datapath will not find -+ * the ld. Use get_local_datapath_no_hash which does not -+ * rely on the hash. -+ */ -+ if (sbrec_datapath_binding_is_updated( -+ dp, SBREC_DATAPATH_BINDING_COL_TUNNEL_KEY)) { -+ if (get_local_datapath_no_hash(&rt_data->local_datapaths, -+ dp->tunnel_key)) { -+ return false; -+ } -+ } -+ } else if (sbrec_datapath_binding_is_updated( -+ dp, SBREC_DATAPATH_BINDING_COL_TUNNEL_KEY) -+ && !sbrec_datapath_binding_is_new(dp)) { -+ /* If the tunnel key is updated, remove the entry (with a wrong -+ * hash) from the map. It will be (properly) added back later. -+ */ -+ if ((ld = get_local_datapath_no_hash(&rt_data->local_datapaths, -+ dp->tunnel_key))) { -+ hmap_remove(&rt_data->local_datapaths, &ld->hmap_node); -+ local_datapath_destroy(ld); -+ } - } - } - -@@ -2637,9 +2675,10 @@ ct_zones_runtime_data_handler(struct engine_node *node, void *data) - struct tracked_lport *t_lport = shash_node->data; - if (strcmp(t_lport->pb->type, "") - && strcmp(t_lport->pb->type, "localport") -+ && strcmp(t_lport->pb->type, "l3gateway") - && strcmp(t_lport->pb->type, "localnet")) { -- /* We allocate zone-id's only to VIF, localport, and localnet -- * lports. */ -+ /* We allocate zone-id's only to VIF, localport, l3gateway, -+ * and localnet lports. */ - continue; - } - -@@ -2803,12 +2842,25 @@ load_balancers_by_dp_init(const struct hmap *local_datapaths, - load_balancers_by_dp_add_one(local_datapaths, - lb->datapaths[i], lb, lbs); - } -+ /* datapath_group column is deprecated. */ - for (size_t i = 0; lb->datapath_group - && i < lb->datapath_group->n_datapaths; i++) { - load_balancers_by_dp_add_one(local_datapaths, - lb->datapath_group->datapaths[i], - lb, lbs); - } -+ for (size_t i = 0; lb->ls_datapath_group -+ && i < lb->ls_datapath_group->n_datapaths; i++) { -+ load_balancers_by_dp_add_one(local_datapaths, -+ lb->ls_datapath_group->datapaths[i], -+ lb, lbs); -+ } -+ for (size_t i = 0; lb->lr_datapath_group -+ && i < lb->lr_datapath_group->n_datapaths; i++) { -+ load_balancers_by_dp_add_one(local_datapaths, -+ lb->lr_datapath_group->datapaths[i], -+ lb, lbs); -+ } - } - return lbs; - } -@@ -3788,6 +3840,11 @@ init_lflow_ctx(struct engine_node *node, - engine_get_input("SB_port_binding", node), - "name"); - -+ struct ovsdb_idl_index *sbrec_port_binding_by_key = -+ engine_ovsdb_node_get_index( -+ engine_get_input("SB_port_binding", node), -+ "key"); +diff --git a/debian/changelog b/debian/changelog +index bbce8a3cb..4f2fabdd7 100644 +--- a/debian/changelog ++++ b/debian/changelog +@@ -1,3 +1,9 @@ ++OVN (23.09.4-1) unstable; urgency=low ++ [ OVN team ] ++ * New upstream version + - struct ovsdb_idl_index *sbrec_logical_flow_by_dp = - engine_ovsdb_node_get_index( - engine_get_input("SB_logical_flow", node), -@@ -3887,6 +3944,7 @@ init_lflow_ctx(struct engine_node *node, - l_ctx_in->sbrec_logical_flow_by_logical_dp_group = - sbrec_logical_flow_by_dp_group; - l_ctx_in->sbrec_port_binding_by_name = sbrec_port_binding_by_name; -+ l_ctx_in->sbrec_port_binding_by_key = sbrec_port_binding_by_key; - l_ctx_in->sbrec_fdb_by_dp_key = sbrec_fdb_by_dp_key; - l_ctx_in->sbrec_mac_binding_by_datapath = sbrec_mac_binding_by_datapath; - l_ctx_in->sbrec_static_mac_binding_by_datapath = -@@ -3905,6 +3963,8 @@ init_lflow_ctx(struct engine_node *node, - l_ctx_in->active_tunnels = &rt_data->active_tunnels; - l_ctx_in->related_lport_ids = &rt_data->related_lports.lport_ids; - l_ctx_in->binding_lports = &rt_data->lbinding_data.lports; -+ l_ctx_in->localnet_learn_fdb = rt_data->localnet_learn_fdb; -+ l_ctx_in->localnet_learn_fdb_changed = rt_data->localnet_learn_fdb_changed; - l_ctx_in->chassis_tunnels = &non_vif_data->chassis_tunnels; - l_ctx_in->lb_hairpin_use_ct_mark = n_opts->lb_hairpin_use_ct_mark; - l_ctx_in->nd_ra_opts = &fo->nd_ra_opts; -@@ -3930,8 +3990,8 @@ en_lflow_output_init(struct engine_node *node OVS_UNUSED, - { - struct ed_type_lflow_output *data = xzalloc(sizeof *data); - ovn_desired_flow_table_init(&data->flow_table); -- ovn_extend_table_init(&data->group_table); -- ovn_extend_table_init(&data->meter_table); -+ ovn_extend_table_init(&data->group_table, "group-table", 0); -+ ovn_extend_table_init(&data->meter_table, "meter-table", 0); - objdep_mgr_init(&data->lflow_deps_mgr); - lflow_conj_ids_init(&data->conj_ids); - uuidset_init(&data->objs_processed); -@@ -4895,11 +4955,6 @@ controller_output_mac_cache_handler(struct engine_node *node, - return true; - } - --struct ovn_controller_exit_args { -- bool *exiting; -- bool *restart; --}; -- - /* Handles sbrec_chassis changes. - * If a new chassis is added or removed return false, so that - * flows are recomputed. For any updates, there is no need for -@@ -4974,9 +5029,7 @@ int - main(int argc, char *argv[]) - { - struct unixctl_server *unixctl; -- bool exiting; -- bool restart; -- struct ovn_controller_exit_args exit_args = {&exiting, &restart}; -+ struct ovn_exit_args exit_args = {}; - int retval; - - /* Read from system-id-override file once on startup. */ -@@ -4996,7 +5049,7 @@ main(int argc, char *argv[]) - if (retval) { - exit(EXIT_FAILURE); - } -- unixctl_command_register("exit", "", 0, 1, ovn_controller_exit, -+ unixctl_command_register("exit", "", 0, 1, ovn_exit_command_callback, - &exit_args); - - daemonize_complete(); -@@ -5049,6 +5102,8 @@ main(int argc, char *argv[]) - = chassis_private_index_create(ovnsb_idl_loop.idl); - struct ovsdb_idl_index *sbrec_multicast_group_by_name_datapath - = mcast_group_index_create(ovnsb_idl_loop.idl); -+ struct ovsdb_idl_index *sbrec_meter_by_name -+ = ovsdb_idl_index_create1(ovnsb_idl_loop.idl, &sbrec_meter_col_name); - struct ovsdb_idl_index *sbrec_logical_flow_by_logical_datapath - = ovsdb_idl_index_create1(ovnsb_idl_loop.idl, - &sbrec_logical_flow_col_logical_datapath); -@@ -5508,10 +5563,8 @@ main(int argc, char *argv[]) - VLOG_INFO("OVN internal version is : [%s]", ovn_version); - - /* Main loop. */ -- exiting = false; -- restart = false; - bool sb_monitor_all = false; -- while (!exiting) { -+ while (!exit_args.exiting) { - memory_run(); - if (memory_should_report()) { - struct simap usage = SIMAP_INITIALIZER(&usage); -@@ -5645,9 +5698,20 @@ main(int argc, char *argv[]) - br_int ? br_int->name : NULL)) { - VLOG_INFO("OVS feature set changed, force recompute."); - engine_set_force_recompute(true); -+ if (ovs_feature_set_discovered()) { -+ uint32_t max_groups = ovs_feature_max_select_groups_get(); -+ uint32_t max_meters = ovs_feature_max_meters_get(); -+ struct ed_type_lflow_output *lflow_out_data = -+ engine_get_internal_data(&en_lflow_output); ++ -- OVN team Tue, 12 Mar 2024 08:35:34 -0400 + -+ ovn_extend_table_reinit(&lflow_out_data->group_table, -+ max_groups); -+ ovn_extend_table_reinit(&lflow_out_data->meter_table, -+ max_meters); -+ } - } - -- if (br_int) { -+ if (br_int && ovs_feature_set_discovered()) { - ct_zones_data = engine_get_data(&en_ct_zones); - if (ct_zones_data && ofctrl_run(br_int, ovs_table, - &ct_zones_data->pending)) { -@@ -5809,6 +5873,13 @@ main(int argc, char *argv[]) - &runtime_data->local_datapaths, - sb_monitor_all); - } -+ if (ovs_idl_txn) { -+ update_qos(sbrec_port_binding_by_name, ovs_idl_txn, -+ ovsrec_port_by_qos, -+ ovsrec_qos_table_get(ovs_idl_loop.idl), -+ &runtime_data->qos_map, -+ ovs_table, bridge_table); -+ } - } - - if (mac_cache_data) { -@@ -5848,7 +5919,7 @@ main(int argc, char *argv[]) - &pflow_output_data->flow_table, - &ct_zones_data->pending, - &lb_data->removed_tuples, -- sbrec_meter_table_get(ovnsb_idl_loop.idl), -+ sbrec_meter_by_name, - ofctrl_seqno_get_req_cfg(), - engine_node_changed(&en_lflow_output), - engine_node_changed(&en_pflow_output)); -@@ -5864,6 +5935,8 @@ main(int argc, char *argv[]) - if_status_mgr_run(if_mgr, binding_data, chassis, - ovsrec_interface_table_get( - ovs_idl_loop.idl), -+ sbrec_port_binding_table_get( -+ ovnsb_idl_loop.idl), - !ovnsb_idl_txn, !ovs_idl_txn); - stopwatch_stop(IF_STATUS_MGR_RUN_STOPWATCH_NAME, - time_msec()); -@@ -5941,7 +6014,7 @@ main(int argc, char *argv[]) - unixctl_server_run(unixctl); - - unixctl_server_wait(unixctl); -- if (exiting || pending_pkt.conn) { -+ if (exit_args.exiting || pending_pkt.conn) { - poll_immediate_wake(); - } - -@@ -5992,7 +6065,7 @@ loop_done: - memory_wait(); - poll_block(); - if (should_service_stop()) { -- exiting = true; -+ exit_args.exiting = true; - } - } - -@@ -6000,7 +6073,7 @@ loop_done: - engine_cleanup(); - - /* It's time to exit. Clean up the databases if we are not restarting */ -- if (!restart) { -+ if (!exit_args.restart) { - bool done = !ovsdb_idl_has_ever_connected(ovnsb_idl_loop.idl); - while (!done) { - update_sb_db(ovs_idl_loop.idl, ovnsb_idl_loop.idl, -@@ -6052,7 +6125,6 @@ loop_done: - } - - free(ovn_version); -- unixctl_server_destroy(unixctl); - lflow_destroy(); - ofctrl_destroy(); - pinctrl_destroy(); -@@ -6077,6 +6149,8 @@ loop_done: - if (cli_system_id) { - free(cli_system_id); - } -+ ovn_exit_args_finish(&exit_args); -+ unixctl_server_destroy(unixctl); - service_stop(); - ovsrcu_exit(); - -@@ -6142,6 +6216,13 @@ parse_options(int argc, char *argv[]) - ssl_ca_cert_file = optarg; - break; - -+ case OPT_SSL_PROTOCOLS: -+ stream_ssl_set_protocols(optarg); -+ break; -+ -+ case OPT_SSL_CIPHERS: -+ stream_ssl_set_ciphers(optarg); -+ break; - - case OPT_PEER_CA_CERT: - stream_ssl_set_peer_ca_cert_file(optarg); -@@ -6156,6 +6237,7 @@ parse_options(int argc, char *argv[]) - break; - - case 'n': -+ free(cli_system_id); - cli_system_id = xstrdup(optarg); - break; - -@@ -6200,16 +6282,6 @@ usage(void) - exit(EXIT_SUCCESS); - } - --static void --ovn_controller_exit(struct unixctl_conn *conn, int argc, -- const char *argv[], void *exit_args_) --{ -- struct ovn_controller_exit_args *exit_args = exit_args_; -- *exit_args->exiting = true; -- *exit_args->restart = argc == 2 && !strcmp(argv[1], "--restart"); -- unixctl_command_reply(conn, NULL); --} -- - static void - ct_zone_list(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *ct_zones_) -diff --git a/controller/physical.c b/controller/physical.c -index 75257bc85..dbce84c4d 100644 ---- a/controller/physical.c -+++ b/controller/physical.c -@@ -341,7 +341,7 @@ get_remote_tunnels(const struct sbrec_port_binding *binding, - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL( - &rl, "Failed to locate tunnel to reach main chassis %s " -- "for port %s. Cloning packets disabled for the chassis.", -+ "for port %s.", - binding->chassis->name, binding->logical_port); - } else { - struct tunnel *tun_elem = xmalloc(sizeof *tun_elem); -@@ -363,7 +363,7 @@ get_remote_tunnels(const struct sbrec_port_binding *binding, - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL( - &rl, "Failed to locate tunnel to reach additional chassis %s " -- "for port %s. Cloning packets disabled for the chassis.", -+ "for port %s.", - binding->additional_chassis[i]->name, binding->logical_port); - continue; - } -@@ -703,22 +703,33 @@ put_replace_chassis_mac_flows(const struct simap *ct_zones, - } - } - --#define VLAN_80211AD_ETHTYPE 0x88a8 --#define VLAN_80211Q_ETHTYPE 0x8100 -+#define VLAN_8021AD_ETHTYPE 0x88a8 -+#define VLAN_8021Q_ETHTYPE 0x8100 - - static void - ofpact_put_push_vlan(struct ofpbuf *ofpacts, const struct smap *options, int tag) - { - const char *ethtype_opt = options ? smap_get(options, "ethtype") : NULL; - -- int ethtype = VLAN_80211Q_ETHTYPE; -+ int ethtype = VLAN_8021Q_ETHTYPE; - if (ethtype_opt) { -- if (!strcasecmp(ethtype_opt, "802.11ad")) { -- ethtype = VLAN_80211AD_ETHTYPE; -- } else if (strcasecmp(ethtype_opt, "802.11q")) { -+ if (!strcasecmp(ethtype_opt, "802.11ad") -+ || !strcasecmp(ethtype_opt, "802.1ad")) { -+ ethtype = VLAN_8021AD_ETHTYPE; -+ } else if (!strcasecmp(ethtype_opt, "802.11q") -+ || !strcasecmp(ethtype_opt, "802.1q")) { -+ ethtype = VLAN_8021Q_ETHTYPE; -+ } else { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); - VLOG_WARN_RL(&rl, "Unknown port ethtype: %s", ethtype_opt); -- } -+ } -+ if (!strcasecmp(ethtype_opt, "802.11ad") -+ || !strcasecmp(ethtype_opt, "802.11q")) { -+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); -+ VLOG_WARN_RL(&rl, "Using incorrect value ethtype: %s for either " -+ "802.1q or 802.1ad please correct this value", -+ ethtype_opt); -+ } - } - - struct ofpact_push_vlan *push_vlan; -@@ -2371,9 +2382,37 @@ physical_run(struct physical_ctx *p_ctx, - } - - put_resubmit(OFTABLE_LOCAL_OUTPUT, &ofpacts); -- - ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 100, 0, &match, - &ofpacts, hc_uuid); -+ -+ /* Set allow rx from tunnel bit. */ -+ put_load(1, MFF_LOG_FLAGS, MLF_RX_FROM_TUNNEL_BIT, 1, &ofpacts); -+ -+ /* Add specif flows for E/W ICMPv{4,6} packets if tunnelled packets -+ * do not fit path MTU. -+ */ -+ put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, &ofpacts); -+ -+ /* IPv4 */ -+ match_init_catchall(&match); -+ match_set_in_port(&match, tun->ofport); -+ match_set_dl_type(&match, htons(ETH_TYPE_IP)); -+ match_set_nw_proto(&match, IPPROTO_ICMP); -+ match_set_icmp_type(&match, 3); -+ match_set_icmp_code(&match, 4); -+ -+ ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 120, 0, &match, -+ &ofpacts, hc_uuid); -+ /* IPv6 */ -+ match_init_catchall(&match); -+ match_set_in_port(&match, tun->ofport); -+ match_set_dl_type(&match, htons(ETH_TYPE_IPV6)); -+ match_set_nw_proto(&match, IPPROTO_ICMPV6); -+ match_set_icmp_type(&match, 2); -+ match_set_icmp_code(&match, 0); -+ -+ ofctrl_add_flow(flow_table, OFTABLE_PHY_TO_LOG, 120, 0, &match, -+ &ofpacts, hc_uuid); - } - - /* Add VXLAN specific rules to transform port keys -diff --git a/controller/pinctrl.c b/controller/pinctrl.c -index ff5a3444c..79b00c878 100644 ---- a/controller/pinctrl.c -+++ b/controller/pinctrl.c -@@ -373,9 +373,13 @@ static const struct sbrec_fdb *fdb_lookup( - uint32_t dp_key, const char *mac); - static void run_put_fdb(struct ovsdb_idl_txn *ovnsb_idl_txn, - struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac, -+ struct ovsdb_idl_index *sbrec_port_binding_by_key, -+ struct ovsdb_idl_index *sbrec_datapath_binding_by_key, - const struct fdb_entry *fdb_e) - OVS_REQUIRES(pinctrl_mutex); - static void run_put_fdbs(struct ovsdb_idl_txn *ovnsb_idl_txn, -+ struct ovsdb_idl_index *sbrec_port_binding_by_key, -+ struct ovsdb_idl_index *sbrec_datapath_binding_by_key, - struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac) - OVS_REQUIRES(pinctrl_mutex); - static void wait_put_fdbs(struct ovsdb_idl_txn *ovnsb_idl_txn); -@@ -1280,11 +1284,25 @@ fill_ipv6_prefix_state(struct ovsdb_idl_txn *ovnsb_idl_txn, - continue; - } - -+ /* To reach this point, the port binding must be a logical router -+ * port. LRPs are configured with a single MAC that is always non-NULL. -+ * Therefore, as long as we are working with a port_binding that was -+ * inserted into the southbound database by northd, we can always -+ * safely extract pb->mac[0] since it will be non-NULL. -+ * -+ * However, if a port_binding was inserted by someone else, then we -+ * need to double-check our assumption first. -+ */ -+ if (pb->n_mac != 1) { -+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); -+ VLOG_ERR_RL(&rl, "Port binding "UUID_FMT" has %"PRIuSIZE" MACs " -+ "instead of 1", UUID_ARGS(&pb->header_.uuid), -+ pb->n_mac); -+ continue; -+ } - struct lport_addresses c_addrs; -- for (size_t j = 0; j < pb->n_mac; j++) { -- if (extract_lsp_addresses(pb->mac[j], &c_addrs)) { -- break; -- } -+ if (!extract_lsp_addresses(pb->mac[0], &c_addrs)) { -+ continue; - } - - pfd = shash_find_data(&ipv6_prefixd, pb->logical_port); -@@ -2850,6 +2868,8 @@ dns_build_ptr_answer( - free(encoded); - } - -+#define DNS_QUERY_TYPE_CLASS_LEN (2 * sizeof(ovs_be16)) -+ - /* Called with in the pinctrl_handler thread context. */ - static void - pinctrl_handle_dns_lookup( -@@ -2911,18 +2931,13 @@ pinctrl_handle_dns_lookup( - goto exit; - } - -- /* Check if there is an additional record present, which is unsupported */ -- if (in_dns_header->arcount) { -- VLOG_DBG_RL(&rl, "Received DNS query with additional records, which" -- " is unsupported"); -- goto exit; -- } -- - struct udp_header *in_udp = dp_packet_l4(pkt_in); - size_t udp_len = ntohs(in_udp->udp_len); - size_t l4_len = dp_packet_l4_size(pkt_in); -+ uint8_t *l4_start = (uint8_t *) in_udp; - uint8_t *end = (uint8_t *)in_udp + MIN(udp_len, l4_len); - uint8_t *in_dns_data = (uint8_t *)(in_dns_header + 1); -+ uint8_t *in_dns_data_start = in_dns_data; - uint8_t *in_queryname = in_dns_data; - uint16_t idx = 0; - struct ds query_name; -@@ -2946,7 +2961,7 @@ pinctrl_handle_dns_lookup( - in_dns_data += idx; - - /* Query should have TYPE and CLASS fields */ -- if (in_dns_data + (2 * sizeof(ovs_be16)) > end) { -+ if (in_dns_data + DNS_QUERY_TYPE_CLASS_LEN > end) { - ds_destroy(&query_name); - goto exit; - } -@@ -2960,6 +2975,10 @@ pinctrl_handle_dns_lookup( - goto exit; - } - -+ uint8_t *rest = in_dns_data + DNS_QUERY_TYPE_CLASS_LEN; -+ uint32_t query_size = rest - in_dns_data_start; -+ uint32_t query_l4_size = rest - l4_start; -+ - uint64_t dp_key = ntohll(pin->flow_metadata.flow.metadata); - const char *answer_data = NULL; - struct shash_node *iter; -@@ -3028,7 +3047,7 @@ pinctrl_handle_dns_lookup( - goto exit; - } - -- uint16_t new_l4_size = ntohs(in_udp->udp_len) + dns_answer.size; -+ uint16_t new_l4_size = query_l4_size + dns_answer.size; - size_t new_packet_size = pkt_in->l4_ofs + new_l4_size; - struct dp_packet pkt_out; - dp_packet_init(&pkt_out, new_packet_size); -@@ -3061,7 +3080,7 @@ pinctrl_handle_dns_lookup( - out_dns_header->arcount = 0; - - /* Copy the Query section. */ -- dp_packet_put(&pkt_out, dp_packet_data(pkt_in), dp_packet_size(pkt_in)); -+ dp_packet_put(&pkt_out, dp_packet_data(pkt_in), query_size); - - /* Copy the answer sections. */ - dp_packet_put(&pkt_out, dns_answer.data, dns_answer.size); -@@ -3577,7 +3596,8 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, - chassis); - bfd_monitor_run(ovnsb_idl_txn, bfd_table, sbrec_port_binding_by_name, - chassis, active_tunnels); -- run_put_fdbs(ovnsb_idl_txn, sbrec_fdb_by_dp_key_mac); -+ run_put_fdbs(ovnsb_idl_txn, sbrec_port_binding_by_key, -+ sbrec_datapath_binding_by_key, sbrec_fdb_by_dp_key_mac); - run_activated_ports(ovnsb_idl_txn, sbrec_datapath_binding_by_key, - sbrec_port_binding_by_key, chassis); - ovs_mutex_unlock(&pinctrl_mutex); -@@ -6226,6 +6246,12 @@ pinctrl_handle_put_nd_ra_opts( - - /* Set the IPv6 payload length and calculate the ICMPv6 checksum. */ - struct ovs_16aligned_ip6_hdr *nh = dp_packet_l3(&pkt_out); -+ -+ /* Set the source to "ff02::1" if the original source is "::". */ -+ if (!memcmp(&nh->ip6_src, &in6addr_any, sizeof in6addr_any)) { -+ memcpy(&nh->ip6_src, &in6addr_all_hosts, sizeof in6addr_all_hosts); -+ } -+ - nh->ip6_plen = htons(userdata->size); - struct ovs_ra_msg *ra = dp_packet_l4(&pkt_out); - ra->icmph.icmp6_cksum = 0; -@@ -6338,26 +6364,31 @@ pinctrl_handle_empty_lb_backends_opts(struct ofpbuf *userdata) - char *protocol = NULL; - char *load_balancer = NULL; - -+ struct empty_lb_backends_event *event = NULL; -+ - while (userdata->size) { - userdata_opt = ofpbuf_try_pull(userdata, sizeof opt_hdr); - if (!userdata_opt) { -- return false; -+ goto cleanup; - } - memcpy(&opt_hdr, userdata_opt, sizeof opt_hdr); - - size_t size = ntohs(opt_hdr.size); - char *userdata_opt_data = ofpbuf_try_pull(userdata, size); - if (!userdata_opt_data) { -- return false; -+ goto cleanup; - } - switch (ntohs(opt_hdr.opt_code)) { - case EMPTY_LB_VIP: -+ free(vip); - vip = xmemdup0(userdata_opt_data, size); - break; - case EMPTY_LB_PROTOCOL: -+ free(protocol); - protocol = xmemdup0(userdata_opt_data, size); - break; - case EMPTY_LB_LOAD_BALANCER: -+ free(load_balancer); - load_balancer = xmemdup0(userdata_opt_data, size); - break; - default: -@@ -6368,36 +6399,39 @@ pinctrl_handle_empty_lb_backends_opts(struct ofpbuf *userdata) - if (!vip || !protocol || !load_balancer) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_WARN_RL(&rl, "missing lb parameters in userdata"); -- free(vip); -- free(protocol); -- free(load_balancer); -- return false; -+ goto cleanup; - } - -- struct empty_lb_backends_event *event; -- - event = pinctrl_find_empty_lb_backends_event(vip, protocol, - load_balancer, hash); -- if (!event) { -- if (hmap_count(&event_table[OVN_EVENT_EMPTY_LB_BACKENDS]) >= 1000) { -- COVERAGE_INC(pinctrl_drop_controller_event); -- return false; -- } -+ if (event) { -+ goto cleanup; -+ } - -- event = xzalloc(sizeof *event); -- hmap_insert(&event_table[OVN_EVENT_EMPTY_LB_BACKENDS], -- &event->hmap_node, hash); -- event->vip = vip; -- event->protocol = protocol; -- event->load_balancer = load_balancer; -- event->timestamp = time_msec(); -- notify_pinctrl_main(); -- } else { -- free(vip); -- free(protocol); -- free(load_balancer); -+ if (hmap_count(&event_table[OVN_EVENT_EMPTY_LB_BACKENDS]) >= 1000) { -+ COVERAGE_INC(pinctrl_drop_controller_event); -+ goto cleanup; - } -- return true; -+ -+ event = xzalloc(sizeof *event); -+ hmap_insert(&event_table[OVN_EVENT_EMPTY_LB_BACKENDS], -+ &event->hmap_node, hash); -+ event->vip = vip; -+ event->protocol = protocol; -+ event->load_balancer = load_balancer; -+ event->timestamp = time_msec(); -+ notify_pinctrl_main(); -+ -+ vip = NULL; -+ protocol = NULL; -+ load_balancer = NULL; -+ -+cleanup: -+ free(vip); -+ free(protocol); -+ free(load_balancer); -+ -+ return event != NULL; - } - - static void -@@ -7755,7 +7789,9 @@ svc_monitors_run(struct rconn *swconn, - if (svc_mon->n_success >= svc_mon->success_count) { - svc_mon->status = SVC_MON_ST_ONLINE; - svc_mon->n_success = 0; -+ svc_mon->n_failures = 0; - } -+ - if (current_time >= svc_mon->next_send_time) { - svc_monitor_send_health_check(swconn, svc_mon); - next_run_time = svc_mon->wait_time; -@@ -7767,6 +7803,7 @@ svc_monitors_run(struct rconn *swconn, - case SVC_MON_S_OFFLINE: - if (svc_mon->n_failures >= svc_mon->failure_count) { - svc_mon->status = SVC_MON_ST_OFFLINE; -+ svc_mon->n_success = 0; - svc_mon->n_failures = 0; - } - -@@ -7812,7 +7849,6 @@ pinctrl_handle_tcp_svc_check(struct rconn *swconn, - return false; - } - -- uint32_t tcp_seq = ntohl(get_16aligned_be32(&th->tcp_seq)); - uint32_t tcp_ack = ntohl(get_16aligned_be32(&th->tcp_ack)); - - if (th->tcp_dst != svc_mon->tp_src) { -@@ -7829,10 +7865,10 @@ pinctrl_handle_tcp_svc_check(struct rconn *swconn, - svc_mon->n_success++; - svc_mon->state = SVC_MON_S_ONLINE; - -- /* Send RST-ACK packet. */ -- svc_monitor_send_tcp_health_check__(swconn, svc_mon, TCP_RST | TCP_ACK, -- htonl(tcp_ack + 1), -- htonl(tcp_seq + 1), th->tcp_dst); -+ /* Send RST packet. */ -+ svc_monitor_send_tcp_health_check__(swconn, svc_mon, TCP_RST, -+ htonl(tcp_ack), -+ htonl(0), th->tcp_dst); - /* Calculate next_send_time. */ - svc_mon->next_send_time = time_msec() + svc_mon->interval; - return true; -@@ -8184,6 +8220,8 @@ fdb_lookup(struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac, uint32_t dp_key, - static void - run_put_fdb(struct ovsdb_idl_txn *ovnsb_idl_txn, - struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac, -+ struct ovsdb_idl_index *sbrec_port_binding_by_key, -+ struct ovsdb_idl_index *sbrec_datapath_binding_by_key, - const struct fdb_entry *fdb_e) - { - /* Convert ethernet argument to string form for database. */ -@@ -8192,14 +8230,28 @@ run_put_fdb(struct ovsdb_idl_txn *ovnsb_idl_txn, - ETH_ADDR_FMT, ETH_ADDR_ARGS(fdb_e->mac)); - - /* Update or add an FDB entry. */ -+ const struct sbrec_port_binding *sb_entry_pb = NULL; -+ const struct sbrec_port_binding *new_entry_pb = NULL; - const struct sbrec_fdb *sb_fdb = - fdb_lookup(sbrec_fdb_by_dp_key_mac, fdb_e->dp_key, mac_string); - if (!sb_fdb) { - sb_fdb = sbrec_fdb_insert(ovnsb_idl_txn); - sbrec_fdb_set_dp_key(sb_fdb, fdb_e->dp_key); - sbrec_fdb_set_mac(sb_fdb, mac_string); -+ } else { -+ /* check whether sb_fdb->port_key is vif or localnet type */ -+ sb_entry_pb = lport_lookup_by_key( -+ sbrec_datapath_binding_by_key, sbrec_port_binding_by_key, -+ sb_fdb->dp_key, sb_fdb->port_key); -+ new_entry_pb = lport_lookup_by_key( -+ sbrec_datapath_binding_by_key, sbrec_port_binding_by_key, -+ fdb_e->dp_key, fdb_e->port_key); -+ } -+ /* Do not have localnet overwrite a previous vif entry */ -+ if (!sb_entry_pb || !new_entry_pb || strcmp(sb_entry_pb->type, "") || -+ strcmp(new_entry_pb->type, "localnet")) { -+ sbrec_fdb_set_port_key(sb_fdb, fdb_e->port_key); - } -- sbrec_fdb_set_port_key(sb_fdb, fdb_e->port_key); - - /* For backward compatibility check if timestamp column is available - * in SB DB. */ -@@ -8210,6 +8262,8 @@ run_put_fdb(struct ovsdb_idl_txn *ovnsb_idl_txn, - - static void - run_put_fdbs(struct ovsdb_idl_txn *ovnsb_idl_txn, -+ struct ovsdb_idl_index *sbrec_port_binding_by_key, -+ struct ovsdb_idl_index *sbrec_datapath_binding_by_key, - struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac) - OVS_REQUIRES(pinctrl_mutex) - { -@@ -8219,7 +8273,9 @@ run_put_fdbs(struct ovsdb_idl_txn *ovnsb_idl_txn, - - const struct fdb_entry *fdb_e; - HMAP_FOR_EACH (fdb_e, hmap_node, &put_fdbs) { -- run_put_fdb(ovnsb_idl_txn, sbrec_fdb_by_dp_key_mac, fdb_e); -+ run_put_fdb(ovnsb_idl_txn, sbrec_fdb_by_dp_key_mac, -+ sbrec_port_binding_by_key, -+ sbrec_datapath_binding_by_key, fdb_e); - } - ovn_fdbs_flush(&put_fdbs); - } -diff --git a/controller/statctrl.c b/controller/statctrl.c -index cb1545cbb..8cce97df8 100644 ---- a/controller/statctrl.c -+++ b/controller/statctrl.c -@@ -233,7 +233,7 @@ statctrl_thread_handler(void *arg) - struct statctrl_ctx *ctx = arg; - - /* OpenFlow connection to the switch. */ -- struct rconn *swconn = rconn_create(5, 0, DSCP_DEFAULT, -+ struct rconn *swconn = rconn_create(0, 0, DSCP_DEFAULT, - 1 << OFP15_VERSION); - - while (!latch_is_set(&ctx->exit_latch)) { -diff --git a/debian/changelog b/debian/changelog -index 96d132784..d61c4a6ef 100644 ---- a/debian/changelog -+++ b/debian/changelog -@@ -1,3 +1,21 @@ -+OVN (23.09.3-1) unstable; urgency=low -+ [ OVN team ] -+ * New upstream version -+ -+ -- OVN team Fri, 01 Mar 2024 14:06:41 -0500 -+ -+OVN (23.09.2-1) unstable; urgency=low -+ [ OVN team ] -+ * New upstream version -+ -+ -- OVN team Fri, 01 Mar 2024 14:06:41 -0500 -+ -+OVN (23.09.1-1) unstable; urgency=low -+ [ OVN team ] -+ * New upstream version -+ -+ -- OVN team Fri, 01 Dec 2023 14:41:31 -0500 -+ - ovn (23.09.0-1) unstable; urgency=low - + OVN (23.09.3-1) unstable; urgency=low + [ OVN team ] * New upstream version -diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c -index e2023c2ba..6db6ce839 100644 ---- a/ic/ovn-ic.c -+++ b/ic/ovn-ic.c -@@ -132,14 +132,18 @@ az_run(struct ic_context *ctx) - return NULL; - } - -- /* Delete old AZ if name changes. Note: if name changed when ovn-ic -- * is not running, one has to manually delete the old AZ with: -+ /* Update old AZ if name changes. Note: if name changed when ovn-ic -+ * is not running, one has to manually delete/update the old AZ with: - * "ovn-ic-sbctl destroy avail ". */ - static char *az_name; - const struct icsbrec_availability_zone *az; - if (az_name && strcmp(az_name, nb_global->name)) { - ICSBREC_AVAILABILITY_ZONE_FOR_EACH (az, ctx->ovnisb_idl) { -- if (!strcmp(az->name, az_name)) { -+ /* AZ name update locally need to update az in ISB. */ -+ if (nb_global->name[0] && !strcmp(az->name, az_name)) { -+ icsbrec_availability_zone_set_name(az, nb_global->name); -+ break; -+ } else if (!nb_global->name[0] && !strcmp(az->name, az_name)) { - icsbrec_availability_zone_delete(az); - break; - } -@@ -1064,12 +1068,15 @@ prefix_is_black_listed(const struct smap *nb_options, - continue; - } - } else { -- struct in6_addr mask = ipv6_create_mask(bl_plen); -- for (int i = 0; i < 16 && mask.s6_addr[i] != 0; i++) { -- if ((prefix->s6_addr[i] & mask.s6_addr[i]) -- != (bl_prefix.s6_addr[i] & mask.s6_addr[i])) { -- continue; -- } -+ struct in6_addr mask = ipv6_create_mask(plen); -+ /* First calculate the difference between bl_prefix and prefix, so -+ * use the bl mask to ensure prefixes are correctly validated. -+ * e.g.: 2005:1734:5678::/50 is a subnet of 2005:1234::/21 */ -+ struct in6_addr m_prefixes = ipv6_addr_bitand(prefix, &bl_prefix); -+ struct in6_addr m_prefix = ipv6_addr_bitand(&m_prefixes, &mask); -+ struct in6_addr m_bl_prefix = ipv6_addr_bitand(&bl_prefix, &mask); -+ if (!ipv6_addr_equals(&m_prefix, &m_bl_prefix)) { -+ continue; - } - } - matched = true; -@@ -1630,13 +1637,18 @@ collect_lr_routes(struct ic_context *ctx, - const struct icnbrec_transit_switch *key; - - struct hmap *routes_ad; -+ const struct icnbrec_transit_switch *t_sw; - for (int i = 0; i < ic_lr->n_isb_pbs; i++) { - isb_pb = ic_lr->isb_pbs[i]; - key = icnbrec_transit_switch_index_init_row( - ctx->icnbrec_transit_switch_by_name); - icnbrec_transit_switch_index_set_name(key, isb_pb->transit_switch); -- ts_name = icnbrec_transit_switch_index_find( -- ctx->icnbrec_transit_switch_by_name, key)->name; -+ t_sw = icnbrec_transit_switch_index_find( -+ ctx->icnbrec_transit_switch_by_name, key); -+ if (!t_sw) { -+ continue; -+ } -+ ts_name = t_sw->name; - icnbrec_transit_switch_index_destroy_row(key); - routes_ad = shash_find_data(routes_ad_by_ts, ts_name); - if (!routes_ad) { -@@ -1841,6 +1853,14 @@ parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) - ssl_ca_cert_file = optarg; - break; - -+ case OPT_SSL_PROTOCOLS: -+ stream_ssl_set_protocols(optarg); -+ break; -+ -+ case OPT_SSL_CIPHERS: -+ stream_ssl_set_ciphers(optarg); -+ break; -+ - case 'd': - ovnsb_db = optarg; - break; -@@ -2216,10 +2236,19 @@ main(int argc, char *argv[]) - ovn_db_run(&ctx); - } - -- ovsdb_idl_loop_commit_and_wait(&ovnnb_idl_loop); -- ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop); -- ovsdb_idl_loop_commit_and_wait(&ovninb_idl_loop); -- ovsdb_idl_loop_commit_and_wait(&ovnisb_idl_loop); -+ int rc1 = ovsdb_idl_loop_commit_and_wait(&ovnnb_idl_loop); -+ int rc2 = ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop); -+ int rc3 = ovsdb_idl_loop_commit_and_wait(&ovninb_idl_loop); -+ int rc4 = ovsdb_idl_loop_commit_and_wait(&ovnisb_idl_loop); -+ if (!rc1 || !rc2 || !rc3 || !rc4) { -+ VLOG_DBG(" a transaction failed in: %s %s %s %s", -+ !rc1 ? "nb" : "", !rc2 ? "sb" : "", -+ !rc3 ? "ic_nb" : "", rc4 ? "ic_sb" : ""); -+ /* A transaction failed. Wake up immediately to give -+ * opportunity to send the proper transaction -+ */ -+ poll_immediate_wake(); -+ } - } else { - /* ovn-ic is paused - * - we still want to handle any db updates and update the -diff --git a/include/ovn/actions.h b/include/ovn/actions.h -index 04bb6ffd0..b99c086e3 100644 ---- a/include/ovn/actions.h -+++ b/include/ovn/actions.h -@@ -75,7 +75,7 @@ struct collector_set_ids; - OVNACT(CT_LB_MARK, ovnact_ct_lb) \ - OVNACT(SELECT, ovnact_select) \ - OVNACT(CT_CLEAR, ovnact_null) \ -- OVNACT(CT_COMMIT_NAT, ovnact_ct_nat) \ -+ OVNACT(CT_COMMIT_NAT, ovnact_ct_commit_nat) \ - OVNACT(CLONE, ovnact_nest) \ - OVNACT(ARP, ovnact_nest) \ - OVNACT(ICMP4, ovnact_nest) \ -@@ -274,7 +274,7 @@ enum ovnact_ct_nat_type { - OVNACT_CT_NAT_UNSPEC, - }; - --/* OVNACT_CT_DNAT, OVNACT_CT_SNAT, OVNACT_CT_COMMIT_NAT. */ -+/* OVNACT_CT_DNAT, OVNACT_CT_SNAT. */ - struct ovnact_ct_nat { - struct ovnact ovnact; - int family; -@@ -296,6 +296,14 @@ struct ovnact_ct_nat { - uint8_t ltable; /* Logical table ID of next table. */ - }; - -+/* OVNACT_CT_COMMIT_NAT. */ -+struct ovnact_ct_commit_nat { -+ struct ovnact ovnact; -+ -+ bool dnat_zone; -+ uint8_t ltable; -+}; -+ - enum ovnact_ct_lb_flag { - OVNACT_CT_LB_FLAG_NONE, - OVNACT_CT_LB_FLAG_SKIP_SNAT, -diff --git a/include/ovn/features.h b/include/ovn/features.h -index 3bf536127..08f1d8288 100644 ---- a/include/ovn/features.h -+++ b/include/ovn/features.h -@@ -26,6 +26,8 @@ - #define OVN_FEATURE_MAC_BINDING_TIMESTAMP "mac-binding-timestamp" - #define OVN_FEATURE_CT_LB_RELATED "ovn-ct-lb-related" - #define OVN_FEATURE_FDB_TIMESTAMP "fdb-timestamp" -+#define OVN_FEATURE_LS_DPG_COLUMN "ls-dpg-column" -+#define OVN_FEATURE_CT_COMMIT_NAT_V2 "ct-commit-nat-v2" - - /* OVS datapath supported features. Based on availability OVN might generate - * different types of openflows. -@@ -48,5 +50,8 @@ void ovs_feature_support_destroy(void); - bool ovs_feature_is_supported(enum ovs_feature_value feature); - bool ovs_feature_support_run(const struct smap *ovs_capabilities, - const char *br_name); -+bool ovs_feature_set_discovered(void); -+uint32_t ovs_feature_max_meters_get(void); -+uint32_t ovs_feature_max_select_groups_get(void); - - #endif -diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h -index a7b64ef67..f07c4c42e 100644 ---- a/include/ovn/logical-fields.h -+++ b/include/ovn/logical-fields.h -@@ -77,6 +77,9 @@ enum mff_log_flags_bits { - MLF_CHECK_PORT_SEC_BIT = 12, - MLF_LOOKUP_COMMIT_ECMP_NH_BIT = 13, - MLF_USE_LB_AFF_SESSION_BIT = 14, -+ MLF_LOCALNET_BIT = 15, -+ MLF_RX_FROM_TUNNEL_BIT = 16, -+ MLF_ICMP_SNAT_BIT = 17, - }; - - /* MFF_LOG_FLAGS_REG flag assignments */ -@@ -124,6 +127,14 @@ enum mff_log_flags { - MLF_LOOKUP_COMMIT_ECMP_NH = (1 << MLF_LOOKUP_COMMIT_ECMP_NH_BIT), - - MLF_USE_LB_AFF_SESSION = (1 << MLF_USE_LB_AFF_SESSION_BIT), -+ -+ /* Indicate that the port is localnet. */ -+ MLF_LOCALNET = (1 << MLF_LOCALNET_BIT), -+ -+ /* Indicate the packet has been received from the tunnel. */ -+ MLF_RX_FROM_TUNNEL = (1 << MLF_RX_FROM_TUNNEL_BIT), -+ -+ MLF_ICMP_SNAT = (1 << MLF_ICMP_SNAT_BIT), - }; - - /* OVN logical fields -diff --git a/lib/actions.c b/lib/actions.c -index b880927b6..1384672f5 100644 ---- a/lib/actions.c -+++ b/lib/actions.c -@@ -1020,16 +1020,29 @@ parse_CT_COMMIT_NAT(struct action_context *ctx) - - if (ctx->pp->cur_ltable >= ctx->pp->n_tables) { - lexer_error(ctx->lexer, -- "\"ct_commit_related\" action not allowed in last table."); -+ "\"ct_commit_nat\" action not allowed in last table."); - return; - } - -- struct ovnact_ct_nat *cn = ovnact_put_CT_COMMIT_NAT(ctx->ovnacts); -- cn->commit = true; -+ struct ovnact_ct_commit_nat *cn = ovnact_put_CT_COMMIT_NAT(ctx->ovnacts); - cn->ltable = ctx->pp->cur_ltable + 1; -- cn->family = AF_UNSPEC; -- cn->type = OVNACT_CT_NAT_UNSPEC; -- cn->port_range.exists = false; -+ cn->dnat_zone = true; -+ -+ if (!lexer_match(ctx->lexer, LEX_T_LPAREN)) { -+ return; -+ } -+ -+ if (lexer_match_id(ctx->lexer, "dnat")) { -+ cn->dnat_zone = true; -+ } else if (lexer_match_id(ctx->lexer, "snat")) { -+ cn->dnat_zone = false; -+ } else { -+ lexer_error(ctx->lexer, "\"ct_commit_nat\" action accepts" -+ " only \"dnat\" or \"snat\" parameter."); -+ return; -+ } -+ -+ lexer_force_match(ctx->lexer, LEX_T_RPAREN); - } - - static void -@@ -1082,9 +1095,10 @@ format_CT_SNAT_IN_CZONE(const struct ovnact_ct_nat *cn, struct ds *s) - } - - static void --format_CT_COMMIT_NAT(const struct ovnact_ct_nat *cn OVS_UNUSED, struct ds *s) -+format_CT_COMMIT_NAT(const struct ovnact_ct_commit_nat *cn, struct ds *s) - { -- ds_put_cstr(s, "ct_commit_nat;"); -+ ds_put_cstr(s, "ct_commit_nat"); -+ ds_put_cstr(s, cn->dnat_zone ? "(dnat);" : "(snat);"); - } - - static void -@@ -1131,8 +1145,20 @@ encode_ct_nat(const struct ovnact_ct_nat *cn, - } - - if (cn->port_range.exists) { -- nat->range.proto.min = cn->port_range.port_lo; -- nat->range.proto.max = cn->port_range.port_hi; -+ nat->range.proto.min = cn->port_range.port_lo; -+ nat->range.proto.max = cn->port_range.port_hi; -+ -+ /* Explicitly set the port selection algorithm to "random". Otherwise -+ * it's up to the datapath to choose how to select the port and that -+ * might create unexpected behavior changes when the datapath defaults -+ * change. -+ * -+ * NOTE: for the userspace datapath the "random" function doesn't -+ * really generate random ports, it uses "hash" under the hood: -+ * https://issues.redhat.com/browse/FDP-269. */ -+ if (nat->range.proto.min && nat->range.proto.max) { -+ nat->flags |= NX_NAT_F_PROTO_RANDOM; -+ } - } - - ofpacts->header = ofpbuf_push_uninit(ofpacts, nat_offset); -@@ -1177,20 +1203,45 @@ encode_CT_SNAT_IN_CZONE(const struct ovnact_ct_nat *cn, - } - - static void --encode_CT_COMMIT_NAT(const struct ovnact_ct_nat *cn, -- const struct ovnact_encode_params *ep, -- struct ofpbuf *ofpacts) -+encode_CT_COMMIT_NAT(const struct ovnact_ct_commit_nat *cn, -+ const struct ovnact_encode_params *ep, -+ struct ofpbuf *ofpacts) - { -- enum mf_field_id zone = ep->is_switch -- ? MFF_LOG_CT_ZONE -- : MFF_LOG_DNAT_ZONE; -- encode_ct_nat(cn, ep, zone, ofpacts); -+ const size_t ct_offset = ofpacts->size; -+ -+ struct ofpact_conntrack *ct = ofpact_put_CT(ofpacts); -+ ct->recirc_table = cn->ltable + first_ptable(ep, ep->pipeline); -+ ct->zone_src.ofs = 0; -+ ct->zone_src.n_bits = 16; -+ ct->flags = NX_CT_F_COMMIT; -+ ct->alg = 0; -+ -+ if (ep->is_switch) { -+ ct->zone_src.field = mf_from_id(MFF_LOG_CT_ZONE); -+ } else { -+ ct->zone_src.field = mf_from_id(cn->dnat_zone -+ ? MFF_LOG_DNAT_ZONE -+ : MFF_LOG_SNAT_ZONE); -+ } -+ -+ struct ofpact_nat *nat = ofpact_put_NAT(ofpacts); -+ nat->range_af = AF_UNSPEC; -+ nat->flags = 0; -+ -+ ct = ofpbuf_at_assert(ofpacts, ct_offset, sizeof *ct); -+ ofpacts->header = ct; -+ ofpact_finish_CT(ofpacts, &ct); - } - - static void - ovnact_ct_nat_free(struct ovnact_ct_nat *ct_nat OVS_UNUSED) - { - } -+ -+static void -+ovnact_ct_commit_nat_free(struct ovnact_ct_commit_nat *cn OVS_UNUSED) -+{ -+} - - static void - parse_ct_lb_action(struct action_context *ctx, bool ct_lb_mark) -@@ -5004,6 +5055,7 @@ encode_COMMIT_LB_AFF(const struct ovnact_commit_lb_aff *lb_aff, - ol->hard_timeout = OFP_FLOW_PERMANENT; - ol->priority = OFP_DEFAULT_PRIORITY; - ol->table_id = OFTABLE_CHK_LB_AFFINITY; -+ ol->cookie = htonll(ep->lflow_uuid.parts[0]); - - /* Match on metadata of the packet that created the new table. */ - ol_spec = ofpbuf_put_zeros(ofpacts, sizeof *ol_spec); -diff --git a/lib/extend-table.c b/lib/extend-table.c -index ebb1a054c..8e79d7177 100644 ---- a/lib/extend-table.c -+++ b/lib/extend-table.c -@@ -17,9 +17,9 @@ - #include - #include - --#include "bitmap.h" - #include "extend-table.h" - #include "hash.h" -+#include "id-pool.h" - #include "lib/uuid.h" - #include "openvswitch/vlog.h" - -@@ -30,13 +30,29 @@ ovn_extend_table_delete_desired(struct ovn_extend_table *table, - struct ovn_extend_table_lflow_to_desired *l); - - void --ovn_extend_table_init(struct ovn_extend_table *table) -+ovn_extend_table_init(struct ovn_extend_table *table, const char *table_name, -+ uint32_t n_ids) - { -- table->table_ids = bitmap_allocate(MAX_EXT_TABLE_ID); -- bitmap_set1(table->table_ids, 0); /* table id 0 is invalid. */ -- hmap_init(&table->desired); -- hmap_init(&table->lflow_to_desired); -- hmap_init(&table->existing); -+ *table = (struct ovn_extend_table) { -+ .name = xstrdup(table_name), -+ .n_ids = n_ids, -+ /* Table id 0 is invalid, set id-pool base to 1. */ -+ .table_ids = id_pool_create(1, n_ids), -+ .desired = HMAP_INITIALIZER(&table->desired), -+ .lflow_to_desired = HMAP_INITIALIZER(&table->lflow_to_desired), -+ .existing = HMAP_INITIALIZER(&table->existing), -+ }; -+} -+ -+void -+ovn_extend_table_reinit(struct ovn_extend_table *table, uint32_t n_ids) -+{ -+ if (n_ids != table->n_ids) { -+ ovn_extend_table_clear(table, true); -+ id_pool_destroy(table->table_ids); -+ table->table_ids = id_pool_create(1, n_ids); -+ table->n_ids = n_ids; -+ } - } - - static struct ovn_extend_table_info * -@@ -117,13 +133,13 @@ ovn_extend_table_add_desired_to_lflow(struct ovn_extend_table *table, - ovs_list_init(&l->desired); - hmap_insert(&table->lflow_to_desired, &l->hmap_node, - uuid_hash(lflow_uuid)); -- VLOG_DBG("%s: add new lflow_to_desired entry "UUID_FMT, -- __func__, UUID_ARGS(lflow_uuid)); -+ VLOG_DBG("%s: table %s: add new lflow_to_desired entry "UUID_FMT, -+ __func__, table->name, UUID_ARGS(lflow_uuid)); - } - - ovs_list_insert(&l->desired, &r->list_node); -- VLOG_DBG("%s: lflow "UUID_FMT" use new item %s, id %"PRIu32, -- __func__, UUID_ARGS(lflow_uuid), r->desired->name, -+ VLOG_DBG("%s: table %s: lflow "UUID_FMT" use new item %s, id %"PRIu32, -+ __func__, table->name, UUID_ARGS(lflow_uuid), r->desired->name, - r->desired->table_id); - } - -@@ -160,10 +176,11 @@ ovn_extend_info_add_lflow_ref(struct ovn_extend_table *table, - } - - static void --ovn_extend_info_del_lflow_ref(struct ovn_extend_table_lflow_ref *r) -+ovn_extend_info_del_lflow_ref(struct ovn_extend_table *table, -+ struct ovn_extend_table_lflow_ref *r) - { -- VLOG_DBG("%s: name %s, lflow "UUID_FMT" n %"PRIuSIZE, __func__, -- r->desired->name, UUID_ARGS(&r->lflow_uuid), -+ VLOG_DBG("%s: table %s: name %s, lflow "UUID_FMT" n %"PRIuSIZE, __func__, -+ table->name, r->desired->name, UUID_ARGS(&r->lflow_uuid), - hmap_count(&r->desired->references)); - hmap_remove(&r->desired->references, &r->hmap_node); - ovs_list_remove(&r->list_node); -@@ -191,8 +208,8 @@ ovn_extend_table_clear(struct ovn_extend_table *table, bool existing) - if (g->peer) { - g->peer->peer = NULL; - } else { -- /* Unset the bitmap because the peer is deleted already. */ -- bitmap_set0(table->table_ids, g->table_id); -+ /* Unset the id because the peer is deleted already. */ -+ id_pool_free_id(table->table_ids, g->table_id); - } - ovn_extend_table_info_destroy(g); - } -@@ -206,7 +223,8 @@ ovn_extend_table_destroy(struct ovn_extend_table *table) - hmap_destroy(&table->lflow_to_desired); - ovn_extend_table_clear(table, true); - hmap_destroy(&table->existing); -- bitmap_free(table->table_ids); -+ id_pool_destroy(table->table_ids); -+ free(table->name); - } - - /* Remove an entry from existing table */ -@@ -221,7 +239,7 @@ ovn_extend_table_remove_existing(struct ovn_extend_table *table, - existing->peer->peer = NULL; - } else { - /* Dealloc the ID. */ -- bitmap_set0(table->table_ids, existing->table_id); -+ id_pool_free_id(table->table_ids, existing->table_id); - } - ovn_extend_table_info_destroy(existing); - } -@@ -234,15 +252,15 @@ ovn_extend_table_delete_desired(struct ovn_extend_table *table, - struct ovn_extend_table_lflow_ref *r; - LIST_FOR_EACH_SAFE (r, list_node, &l->desired) { - struct ovn_extend_table_info *e = r->desired; -- ovn_extend_info_del_lflow_ref(r); -+ ovn_extend_info_del_lflow_ref(table, r); - if (hmap_is_empty(&e->references)) { -- VLOG_DBG("%s: %s, "UUID_FMT, __func__, -- e->name, UUID_ARGS(&l->lflow_uuid)); -+ VLOG_DBG("%s: table %s: %s, "UUID_FMT, __func__, -+ table->name, e->name, UUID_ARGS(&l->lflow_uuid)); - hmap_remove(&table->desired, &e->hmap_node); - if (e->peer) { - e->peer->peer = NULL; - } else { -- bitmap_set0(table->table_ids, e->table_id); -+ id_pool_free_id(table->table_ids, e->table_id); - } - ovn_extend_table_info_destroy(e); - } -@@ -284,7 +302,7 @@ ovn_extend_table_sync(struct ovn_extend_table *table) - } - } - --/* Assign a new table ID for the table information from the bitmap. -+/* Assign a new table ID for the table information from the ID pool. - * If it already exists, return the old ID. */ - uint32_t - ovn_extend_table_assign_id(struct ovn_extend_table *table, const char *name, -@@ -298,9 +316,9 @@ ovn_extend_table_assign_id(struct ovn_extend_table *table, const char *name, - /* Check whether we have non installed but allocated group_id. */ - HMAP_FOR_EACH_WITH_HASH (table_info, hmap_node, hash, &table->desired) { - if (!strcmp(table_info->name, name)) { -- VLOG_DBG("ovn_externd_table_assign_id: reuse old id %"PRIu32 -- " for %s, used by lflow "UUID_FMT, -- table_info->table_id, table_info->name, -+ VLOG_DBG("ovn_extend_table_assign_id: table %s: " -+ "reuse old id %"PRIu32" for %s, used by lflow "UUID_FMT, -+ table->name, table_info->table_id, table_info->name, - UUID_ARGS(&lflow_uuid)); - ovn_extend_info_add_lflow_ref(table, table_info, &lflow_uuid); - return table_info->table_id; -@@ -320,15 +338,13 @@ ovn_extend_table_assign_id(struct ovn_extend_table *table, const char *name, - - if (!existing_info) { - /* Reserve a new id. */ -- table_id = bitmap_scan(table->table_ids, 0, 1, MAX_EXT_TABLE_ID + 1); -- } -+ if (!id_pool_alloc_id(table->table_ids, &table_id)) { -+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); - -- if (table_id == MAX_EXT_TABLE_ID + 1) { -- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); -- VLOG_ERR_RL(&rl, "%"PRIu32" out of table ids.", table_id); -- return EXT_TABLE_ID_INVALID; -+ VLOG_ERR_RL(&rl, "table %s: out of table ids.", table->name); -+ return EXT_TABLE_ID_INVALID; -+ } - } -- bitmap_set1(table->table_ids, table_id); - - table_info = ovn_extend_table_info_alloc(name, table_id, existing_info, - hash); -diff --git a/lib/extend-table.h b/lib/extend-table.h -index b43a146b4..90e6e470d 100644 ---- a/lib/extend-table.h -+++ b/lib/extend-table.h -@@ -17,18 +17,21 @@ - #ifndef EXTEND_TABLE_H - #define EXTEND_TABLE_H 1 - --#define MAX_EXT_TABLE_ID 65535 - #define EXT_TABLE_ID_INVALID 0 - - #include "openvswitch/hmap.h" - #include "openvswitch/list.h" - #include "openvswitch/uuid.h" - -+struct id_pool; -+ - /* Used to manage expansion tables associated with Flow table, - * such as the Group Table or Meter Table. */ - struct ovn_extend_table { -- unsigned long *table_ids; /* Used as a bitmap with value set -- * for allocated ids in either desired or -+ char *name; /* Used to identify this table in a user friendly way, -+ * e.g., for logging. */ -+ uint32_t n_ids; -+ struct id_pool *table_ids; /* Used to allocate ids in either desired or - * existing (or both). If the same "name" - * exists in both desired and existing tables, - * they must share the same ID. The "peer" -@@ -81,7 +84,9 @@ struct ovn_extend_table_lflow_ref { - struct ovn_extend_table_info *desired; - }; - --void ovn_extend_table_init(struct ovn_extend_table *); -+void ovn_extend_table_init(struct ovn_extend_table *, const char *table_name, -+ uint32_t n_ids); -+void ovn_extend_table_reinit(struct ovn_extend_table *, uint32_t n_ids); - - void ovn_extend_table_destroy(struct ovn_extend_table *); - -diff --git a/lib/features.c b/lib/features.c -index d24e8f6c5..d391930c6 100644 ---- a/lib/features.c -+++ b/lib/features.c -@@ -27,6 +27,7 @@ - #include "openvswitch/rconn.h" - #include "openvswitch/ofp-msgs.h" - #include "openvswitch/ofp-meter.h" -+#include "openvswitch/ofp-group.h" - #include "openvswitch/ofp-util.h" - #include "ovn/features.h" - -@@ -81,6 +82,18 @@ static struct ovs_feature all_ovs_features[] = { - /* A bitmap of OVS features that have been detected as 'supported'. */ - static uint32_t supported_ovs_features; - -+/* Last set of received feature replies. */ -+static struct ofputil_meter_features ovs_meter_features_reply; -+static struct ofputil_group_features ovs_group_features_reply; -+ -+/* Currently discovered set of features. */ -+static struct ofputil_meter_features ovs_meter_features; -+static struct ofputil_group_features ovs_group_features; -+ -+/* Number of features replies still expected to receive for the requests -+ * we sent already. */ -+static uint32_t n_features_reply_expected; -+ - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); - - /* ovs-vswitchd connection. */ -@@ -140,16 +153,26 @@ ovs_feature_get_openflow_cap(const char *br_name) - - rconn_run(swconn); - if (!rconn_is_connected(swconn)) { -+ rconn_run_wait(swconn); -+ rconn_recv_wait(swconn); - return false; - } - - /* send new requests just after reconnect. */ - if (conn_seq_no != rconn_get_connection_seqno(swconn)) { -- /* dump datapath meter capabilities. */ -+ n_features_reply_expected = 0; -+ -+ /* Dump OpenFlow switch meter capabilities. */ - msg = ofpraw_alloc(OFPRAW_OFPST13_METER_FEATURES_REQUEST, - rconn_get_version(swconn), 0); - rconn_send(swconn, msg, NULL); -+ n_features_reply_expected++; -+ /* Dump OpenFlow switch group capabilities. */ -+ msg = ofputil_encode_group_features_request(rconn_get_version(swconn)); -+ rconn_send(swconn, msg, NULL); -+ n_features_reply_expected++; - } -+ conn_seq_no = rconn_get_connection_seqno(swconn); - - bool ret = false; - for (int i = 0; i < 50; i++) { -@@ -163,21 +186,13 @@ ovs_feature_get_openflow_cap(const char *br_name) - ofptype_decode(&type, oh); - - if (type == OFPTYPE_METER_FEATURES_STATS_REPLY) { -- struct ofputil_meter_features mf; -- ofputil_decode_meter_features(oh, &mf); -- -- bool old_state = supported_ovs_features & OVS_DP_METER_SUPPORT; -- bool new_state = mf.max_meters > 0; -- -- if (old_state != new_state) { -- ret = true; -- if (new_state) { -- supported_ovs_features |= OVS_DP_METER_SUPPORT; -- } else { -- supported_ovs_features &= ~OVS_DP_METER_SUPPORT; -- } -- } -- conn_seq_no = rconn_get_connection_seqno(swconn); -+ ofputil_decode_meter_features(oh, &ovs_meter_features_reply); -+ ovs_assert(n_features_reply_expected); -+ n_features_reply_expected--; -+ } else if (type == OFPTYPE_GROUP_FEATURES_STATS_REPLY) { -+ ofputil_decode_group_features_reply(oh, &ovs_group_features_reply); -+ ovs_assert(n_features_reply_expected); -+ n_features_reply_expected--; - } else if (type == OFPTYPE_ECHO_REQUEST) { - rconn_send(swconn, ofputil_encode_echo_reply(oh), NULL); - } -@@ -186,6 +201,26 @@ ovs_feature_get_openflow_cap(const char *br_name) - rconn_run_wait(swconn); - rconn_recv_wait(swconn); - -+ /* If all feature replies were received, update the set of supported -+ * features. */ -+ if (!n_features_reply_expected) { -+ if (memcmp(&ovs_meter_features, &ovs_meter_features_reply, -+ sizeof ovs_meter_features_reply)) { -+ ovs_meter_features = ovs_meter_features_reply; -+ if (ovs_meter_features.max_meters) { -+ supported_ovs_features |= OVS_DP_METER_SUPPORT; -+ } else { -+ supported_ovs_features &= ~OVS_DP_METER_SUPPORT; -+ } -+ ret = true; -+ } -+ if (memcmp(&ovs_group_features, &ovs_group_features_reply, -+ sizeof ovs_group_features_reply)) { -+ ovs_group_features = ovs_group_features_reply; -+ ret = true; -+ } -+ } -+ - return ret; - } - -@@ -229,3 +264,26 @@ ovs_feature_support_run(const struct smap *ovs_capabilities, - } - return updated; - } -+ -+bool -+ovs_feature_set_discovered(void) -+{ -+ /* The supported feature set has been discovered if we're connected -+ * to OVS and it replied to all our feature request messages. */ -+ return swconn && rconn_is_connected(swconn) && -+ n_features_reply_expected == 0; -+} -+ -+/* Returns the number of meters the OVS datapath supports. */ -+uint32_t -+ovs_feature_max_meters_get(void) -+{ -+ return ovs_meter_features.max_meters; -+} -+ -+/* Returns the number of select groups the OVS datapath supports. */ -+uint32_t -+ovs_feature_max_select_groups_get(void) -+{ -+ return ovs_group_features.max_groups[OFPGT11_SELECT]; -+} -diff --git a/lib/logical-fields.c b/lib/logical-fields.c -index fd509d9ee..20219a67a 100644 ---- a/lib/logical-fields.c -+++ b/lib/logical-fields.c -@@ -129,6 +129,16 @@ ovn_init_symtab(struct shash *symtab) - MLF_USE_SNAT_ZONE); - expr_symtab_add_subfield(symtab, "flags.use_snat_zone", NULL, - flags_str); -+ snprintf(flags_str, sizeof flags_str, "flags[%d]", -+ MLF_LOCALNET_BIT); -+ expr_symtab_add_subfield(symtab, "flags.localnet", NULL, -+ flags_str); -+ snprintf(flags_str, sizeof flags_str, "flags[%d]", -+ MLF_ICMP_SNAT_BIT); -+ expr_symtab_add_subfield(symtab, "flags.icmp_snat", NULL, -+ flags_str); -+ snprintf(flags_str, sizeof flags_str, "flags[%d]", MLF_RX_FROM_TUNNEL_BIT); -+ expr_symtab_add_subfield(symtab, "flags.tunnel_rx", NULL, flags_str); - - /* Connection tracking state. */ - expr_symtab_add_field_scoped(symtab, "ct_mark", MFF_CT_MARK, NULL, false, -diff --git a/lib/memory-trim.c b/lib/memory-trim.c -index d8c6b4743..be8983fa7 100644 ---- a/lib/memory-trim.c -+++ b/lib/memory-trim.c -@@ -71,13 +71,14 @@ memory_trimmer_can_run(struct memory_trimmer *mt) - } - - long long int now = time_msec(); -- if (now < mt->last_active_ms || now < mt->trim_timeout_ms) { -+ if (now < mt->last_active_ms) { - VLOG_WARN_RL(&rl, "Detected last active timestamp overflow"); - mt->recently_active = false; - return true; - } - -- if (now - mt->trim_timeout_ms >= mt->last_active_ms) { -+ if (now > mt->trim_timeout_ms -+ && now - mt->trim_timeout_ms >= mt->last_active_ms) { - VLOG_INFO_RL(&rl, "Detected inactivity " - "(last active %lld ms ago): trimming memory", - now - mt->last_active_ms); -diff --git a/lib/ovn-util.c b/lib/ovn-util.c -index ffe295696..33105202f 100644 ---- a/lib/ovn-util.c -+++ b/lib/ovn-util.c -@@ -1302,3 +1302,34 @@ sorted_array_apply_diff(const struct sorted_array *a1, - apply_callback(arg, a2->arr[idx2], false); - } - } -+ -+/* Call for the unixctl command that will store the connection and -+ * set the appropriate conditions. */ -+void -+ovn_exit_command_callback(struct unixctl_conn *conn, int argc, -+ const char *argv[], void *exit_args_) -+{ -+ struct ovn_exit_args *exit_args = exit_args_; -+ -+ exit_args->n_conns++; -+ exit_args->conns = xrealloc(exit_args->conns, -+ exit_args->n_conns * sizeof *exit_args->conns); -+ -+ exit_args->exiting = true; -+ exit_args->conns[exit_args->n_conns - 1] = conn; -+ -+ if (!exit_args->restart) { -+ exit_args->restart = argc == 2 && !strcmp(argv[1], "--restart"); -+ } -+} -+ -+/* Reply to all waiting unixctl connections and free the connection array. -+ * This function should be called after the heaviest cleanup has finished. */ -+void -+ovn_exit_args_finish(struct ovn_exit_args *exit_args) -+{ -+ for (size_t i = 0; i < exit_args->n_conns; i++) { -+ unixctl_command_reply(exit_args->conns[i], NULL); -+ } -+ free(exit_args->conns); -+} -diff --git a/lib/ovn-util.h b/lib/ovn-util.h -index 16f18353d..bff50dbde 100644 ---- a/lib/ovn-util.h -+++ b/lib/ovn-util.h -@@ -474,4 +474,17 @@ void sorted_array_apply_diff(const struct sorted_array *a1, - const char *item, - bool add), - const void *arg); -+ -+/* Utilities around properly handling exit command. */ -+struct ovn_exit_args { -+ struct unixctl_conn **conns; -+ size_t n_conns; -+ bool exiting; -+ bool restart; -+}; -+ -+void ovn_exit_command_callback(struct unixctl_conn *conn, int argc, -+ const char *argv[], void *exit_args_); -+void ovn_exit_args_finish(struct ovn_exit_args *exit_args); -+ - #endif /* OVN_UTIL_H */ -diff --git a/northd/en-lb-data.c b/northd/en-lb-data.c -index 250cec848..d06f46a54 100644 ---- a/northd/en-lb-data.c -+++ b/northd/en-lb-data.c -@@ -144,6 +144,12 @@ lb_data_load_balancer_handler(struct engine_node *node, void *data) - - const struct nbrec_load_balancer *tracked_lb; - NBREC_LOAD_BALANCER_TABLE_FOR_EACH_TRACKED (tracked_lb, nb_lb_table) { -+ /* "New" + "Deleted" is a no-op. */ -+ if (nbrec_load_balancer_is_new(tracked_lb) -+ && nbrec_load_balancer_is_deleted(tracked_lb)) { -+ continue; -+ } -+ - struct ovn_northd_lb *lb; - if (nbrec_load_balancer_is_new(tracked_lb)) { - /* New load balancer. */ -@@ -153,19 +159,22 @@ lb_data_load_balancer_handler(struct engine_node *node, void *data) - add_crupdated_lb_to_tracked_data(lb, trk_lb_data, - lb->health_checks); - trk_lb_data->has_routable_lb |= lb->routable; -- } else if (nbrec_load_balancer_is_deleted(tracked_lb)) { -- lb = ovn_northd_lb_find(&lb_data->lbs, -- &tracked_lb->header_.uuid); -- ovs_assert(lb); -+ continue; -+ } -+ -+ /* Protect against "spurious" deletes reported by the IDL. */ -+ lb = ovn_northd_lb_find(&lb_data->lbs, &tracked_lb->header_.uuid); -+ if (!lb) { -+ continue; -+ } -+ -+ if (nbrec_load_balancer_is_deleted(tracked_lb)) { - hmap_remove(&lb_data->lbs, &lb->hmap_node); - add_deleted_lb_to_tracked_data(lb, trk_lb_data, - lb->health_checks); - trk_lb_data->has_routable_lb |= lb->routable; - } else { - /* Load balancer updated. */ -- lb = ovn_northd_lb_find(&lb_data->lbs, -- &tracked_lb->header_.uuid); -- ovs_assert(lb); - bool health_checks = lb->health_checks; - struct sset old_ips_v4 = SSET_INITIALIZER(&old_ips_v4); - struct sset old_ips_v6 = SSET_INITIALIZER(&old_ips_v6); -@@ -217,6 +226,12 @@ lb_data_load_balancer_group_handler(struct engine_node *node, void *data) - const struct nbrec_load_balancer_group *tracked_lb_group; - NBREC_LOAD_BALANCER_GROUP_TABLE_FOR_EACH_TRACKED (tracked_lb_group, - nb_lbg_table) { -+ /* "New" + "Deleted" is a no-op. */ -+ if (nbrec_load_balancer_group_is_new(tracked_lb_group) -+ && nbrec_load_balancer_group_is_deleted(tracked_lb_group)) { -+ continue; -+ } -+ - if (nbrec_load_balancer_group_is_new(tracked_lb_group)) { - struct ovn_lb_group *lb_group = - create_lb_group(tracked_lb_group, &lb_data->lbs, -@@ -228,21 +243,22 @@ lb_data_load_balancer_group_handler(struct engine_node *node, void *data) - } - - trk_lb_data->has_routable_lb |= lb_group->has_routable_lb; -- } else if (nbrec_load_balancer_group_is_deleted(tracked_lb_group)) { -- struct ovn_lb_group *lb_group; -- lb_group = ovn_lb_group_find(&lb_data->lbgrps, -- &tracked_lb_group->header_.uuid); -- ovs_assert(lb_group); -+ continue; -+ } -+ -+ /* Protect against "spurious" deletes reported by the IDL. */ -+ struct ovn_lb_group *lb_group; -+ lb_group = ovn_lb_group_find(&lb_data->lbgrps, -+ &tracked_lb_group->header_.uuid); -+ if (!lb_group) { -+ continue; -+ } -+ -+ if (nbrec_load_balancer_group_is_deleted(tracked_lb_group)) { - hmap_remove(&lb_data->lbgrps, &lb_group->hmap_node); - add_deleted_lbgrp_to_tracked_data(lb_group, trk_lb_data); - trk_lb_data->has_routable_lb |= lb_group->has_routable_lb; - } else { -- -- struct ovn_lb_group *lb_group; -- lb_group = ovn_lb_group_find(&lb_data->lbgrps, -- &tracked_lb_group->header_.uuid); -- ovs_assert(lb_group); -- - /* Determine the lbs which are added or deleted for this - * lb group and add them to tracked data. - * Eg. If an lb group lbg1 before the update had [lb1, lb2, lb3] -diff --git a/northd/en-meters.c b/northd/en-meters.c -index aabd002b6..793a46335 100644 ---- a/northd/en-meters.c -+++ b/northd/en-meters.c -@@ -203,9 +203,13 @@ sync_acl_fair_meter(struct ovsdb_idl_txn *ovnsb_txn, - const struct nbrec_acl *acl, struct shash *sb_meters, - struct sset *used_sb_meters) - { -- const struct nbrec_meter *nb_meter = -- fair_meter_lookup_by_name(meter_groups, acl->meter); -+ const struct nbrec_meter *nb_meter; -+ -+ if (!acl->log || !acl->meter) { -+ return; -+ } - -+ nb_meter = fair_meter_lookup_by_name(meter_groups, acl->meter); - if (!nb_meter) { - return; - } -diff --git a/northd/en-sync-sb.c b/northd/en-sync-sb.c -index aae396a43..2ec3bf54f 100644 ---- a/northd/en-sync-sb.c -+++ b/northd/en-sync-sb.c -@@ -220,7 +220,8 @@ en_sync_to_sb_lb_run(struct engine_node *node, void *data OVS_UNUSED) - struct northd_data *northd_data = engine_get_input_data("northd", node); - - sync_lbs(eng_ctx->ovnsb_idl_txn, sb_load_balancer_table, -- &northd_data->ls_datapaths, &northd_data->lb_datapaths_map); -+ &northd_data->ls_datapaths, &northd_data->lr_datapaths, -+ &northd_data->lb_datapaths_map, &northd_data->features); - engine_set_node_state(node, EN_UPDATED); - } - -@@ -248,6 +249,23 @@ sync_to_sb_lb_northd_handler(struct engine_node *node, void *data OVS_UNUSED) - return true; - } - -+bool -+sync_to_sb_lb_sb_load_balancer(struct engine_node *node, void *data OVS_UNUSED) -+{ -+ const struct sbrec_load_balancer_table *sb_load_balancer_table = -+ EN_OVSDB_GET(engine_get_input("SB_load_balancer", node)); -+ -+ /* The only reason to handle SB.Load_Balancer updates is to detect -+ * spurious records being created in clustered databases due to -+ * lack of indexing on the SB.Load_Balancer table. All other changes -+ * are valid and performed by northd, the only write-client for -+ * this table. */ -+ if (check_sb_lb_duplicates(sb_load_balancer_table)) { -+ return false; -+ } -+ return true; -+} -+ - /* sync_to_sb_pb engine node functions. - * This engine node syncs the SB Port Bindings (partly). - * en_northd engine create the SB Port binding rows and -diff --git a/northd/en-sync-sb.h b/northd/en-sync-sb.h -index f08565eee..3bcbb8259 100644 ---- a/northd/en-sync-sb.h -+++ b/northd/en-sync-sb.h -@@ -21,6 +21,8 @@ void *en_sync_to_sb_lb_init(struct engine_node *, struct engine_arg *); - void en_sync_to_sb_lb_run(struct engine_node *, void *data); - void en_sync_to_sb_lb_cleanup(void *data); - bool sync_to_sb_lb_northd_handler(struct engine_node *, void *data OVS_UNUSED); -+bool sync_to_sb_lb_sb_load_balancer(struct engine_node *, -+ void *data OVS_UNUSED); - - void *en_sync_to_sb_pb_init(struct engine_node *, struct engine_arg *); - void en_sync_to_sb_pb_run(struct engine_node *, void *data); -diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c -index 8b0817117..04df0b06c 100644 ---- a/northd/inc-proc-northd.c -+++ b/northd/inc-proc-northd.c -@@ -230,7 +230,8 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb, - - engine_add_input(&en_sync_to_sb_lb, &en_northd, - sync_to_sb_lb_northd_handler); -- engine_add_input(&en_sync_to_sb_lb, &en_sb_load_balancer, NULL); -+ engine_add_input(&en_sync_to_sb_lb, &en_sb_load_balancer, -+ sync_to_sb_lb_sb_load_balancer); - - engine_add_input(&en_sync_to_sb_pb, &en_northd, - sync_to_sb_pb_northd_handler); -diff --git a/northd/northd.c b/northd/northd.c -index 04afe62a8..b1546f7bf 100644 ---- a/northd/northd.c -+++ b/northd/northd.c -@@ -491,6 +491,24 @@ build_chassis_features(const struct sbrec_chassis_table *sbrec_chassis_table, - chassis_features->fdb_timestamp) { - chassis_features->fdb_timestamp = false; - } -+ -+ bool ls_dpg_column = -+ smap_get_bool(&chassis->other_config, -+ OVN_FEATURE_LS_DPG_COLUMN, -+ false); -+ if (!ls_dpg_column && -+ chassis_features->ls_dpg_column) { -+ chassis_features->ls_dpg_column = false; -+ } -+ -+ bool ct_commit_nat_v2 = -+ smap_get_bool(&chassis->other_config, -+ OVN_FEATURE_CT_COMMIT_NAT_V2, -+ false); -+ if (!ct_commit_nat_v2 && -+ chassis_features->ct_commit_nat_v2) { -+ chassis_features->ct_commit_nat_v2 = false; -+ } - } - } - -@@ -4511,6 +4529,7 @@ struct sb_lb { - - const struct sbrec_load_balancer *slb; - struct ovn_dp_group *dpg; -+ struct ovn_dp_group *lr_dpg; - struct uuid lb_uuid; - }; - -@@ -4533,10 +4552,13 @@ find_slb_in_sb_lbs(struct hmap *sb_lbs, const struct uuid *lb_uuid) - void - sync_lbs(struct ovsdb_idl_txn *ovnsb_txn, - const struct sbrec_load_balancer_table *sbrec_load_balancer_table, -- struct ovn_datapaths *ls_datapaths, struct hmap *lb_dps_map) -+ struct ovn_datapaths *ls_datapaths, -+ struct ovn_datapaths *lr_datapaths, -+ struct hmap *lb_dps_map, -+ struct chassis_features *chassis_features) - { -- struct hmap dp_groups = HMAP_INITIALIZER(&dp_groups); -- size_t bitmap_len = ods_size(ls_datapaths); -+ struct hmap ls_dp_groups = HMAP_INITIALIZER(&ls_dp_groups); -+ struct hmap lr_dp_groups = HMAP_INITIALIZER(&lr_dp_groups); - struct ovn_lb_datapaths *lb_dps; - struct hmap sb_lbs = HMAP_INITIALIZER(&sb_lbs); - -@@ -4554,7 +4576,8 @@ sync_lbs(struct ovsdb_idl_txn *ovnsb_txn, - } - - /* Delete any SB load balancer entries that refer to NB load balancers -- * that don't exist anymore or are not applied to switches anymore. -+ * that don't exist anymore or are not applied to switches/routers -+ * anymore. - * - * There is also a special case in which duplicate LBs might be created - * in the SB, e.g., due to the fact that OVSDB only ensures -@@ -4562,7 +4585,8 @@ sync_lbs(struct ovsdb_idl_txn *ovnsb_txn, - * are not indexed in any way. - */ - lb_dps = ovn_lb_datapaths_find(lb_dps_map, &lb_uuid); -- if (!lb_dps || !lb_dps->n_nb_ls || !hmapx_add(&existing_lbs, lb_dps)) { -+ if (!lb_dps || (!lb_dps->n_nb_ls && !lb_dps->n_nb_lr) || -+ !hmapx_add(&existing_lbs, lb_dps)) { - sbrec_load_balancer_delete(sbrec_lb); - continue; - } -@@ -4573,12 +4597,26 @@ sync_lbs(struct ovsdb_idl_txn *ovnsb_txn, - hmap_insert(&sb_lbs, &sb_lb->hmap_node, uuid_hash(&lb_uuid)); - - /* Find or create datapath group for this load balancer. */ -- sb_lb->dpg = ovn_dp_group_get_or_create(ovnsb_txn, &dp_groups, -- sb_lb->slb->datapath_group, -- lb_dps->n_nb_ls, -- lb_dps->nb_ls_map, -- bitmap_len, true, -- ls_datapaths, NULL); -+ if (lb_dps->n_nb_ls) { -+ struct sbrec_logical_dp_group *ls_datapath_group -+ = chassis_features->ls_dpg_column -+ ? sb_lb->slb->ls_datapath_group -+ : sb_lb->slb->datapath_group; /* deprecated */ -+ sb_lb->dpg = ovn_dp_group_get_or_create( -+ ovnsb_txn, &ls_dp_groups, -+ ls_datapath_group, -+ lb_dps->n_nb_ls, lb_dps->nb_ls_map, -+ ods_size(ls_datapaths), true, -+ ls_datapaths, NULL); -+ } -+ if (lb_dps->n_nb_lr) { -+ sb_lb->lr_dpg = ovn_dp_group_get_or_create( -+ ovnsb_txn, &lr_dp_groups, -+ sb_lb->slb->lr_datapath_group, -+ lb_dps->n_nb_lr, lb_dps->nb_lr_map, -+ ods_size(lr_datapaths), false, -+ NULL, lr_datapaths); -+ } - } - hmapx_destroy(&existing_lbs); - -@@ -4586,7 +4624,7 @@ sync_lbs(struct ovsdb_idl_txn *ovnsb_txn, - * the SB load balancer columns. */ - HMAP_FOR_EACH (lb_dps, hmap_node, lb_dps_map) { - -- if (!lb_dps->n_nb_ls) { -+ if (!lb_dps->n_nb_ls && !lb_dps->n_nb_lr) { - continue; - } - -@@ -4599,8 +4637,8 @@ sync_lbs(struct ovsdb_idl_txn *ovnsb_txn, - - struct sb_lb *sb_lb = find_slb_in_sb_lbs(&sb_lbs, - &lb_dps->lb->nlb->header_.uuid); -- ovs_assert(!sb_lb || (sb_lb->slb && sb_lb->dpg)); -- struct ovn_dp_group *lb_dpg = NULL; -+ ovs_assert(!sb_lb || (sb_lb->slb && (sb_lb->dpg || sb_lb->lr_dpg))); -+ struct ovn_dp_group *lb_dpg = NULL, *lb_lr_dpg = NULL; - if (!sb_lb) { - sbrec_lb = sbrec_load_balancer_insert(ovnsb_txn); - char *lb_id = xasprintf( -@@ -4612,15 +4650,29 @@ sync_lbs(struct ovsdb_idl_txn *ovnsb_txn, - } else { - sbrec_lb = sb_lb->slb; - lb_dpg = sb_lb->dpg; -+ lb_lr_dpg = sb_lb->lr_dpg; - } - - /* Find or create datapath group for this load balancer. */ -- if (!lb_dpg) { -- lb_dpg = ovn_dp_group_get_or_create(ovnsb_txn, &dp_groups, -- sbrec_lb->datapath_group, -- lb_dps->n_nb_ls, -- lb_dps->nb_ls_map, bitmap_len, -- true, ls_datapaths, NULL); -+ if (!lb_dpg && lb_dps->n_nb_ls) { -+ struct sbrec_logical_dp_group *ls_datapath_group -+ = chassis_features->ls_dpg_column -+ ? sbrec_lb->ls_datapath_group -+ : sbrec_lb->datapath_group; /* deprecated */ -+ lb_dpg = ovn_dp_group_get_or_create( -+ ovnsb_txn, &ls_dp_groups, -+ ls_datapath_group, -+ lb_dps->n_nb_ls, lb_dps->nb_ls_map, -+ ods_size(ls_datapaths), true, -+ ls_datapaths, NULL); -+ } -+ if (!lb_lr_dpg && lb_dps->n_nb_lr) { -+ lb_lr_dpg = ovn_dp_group_get_or_create( -+ ovnsb_txn, &lr_dp_groups, -+ sbrec_lb->lr_datapath_group, -+ lb_dps->n_nb_lr, lb_dps->nb_lr_map, -+ ods_size(lr_datapaths), false, -+ NULL, lr_datapaths); - } - - /* Update columns. */ -@@ -4628,7 +4680,23 @@ sync_lbs(struct ovsdb_idl_txn *ovnsb_txn, - sbrec_load_balancer_set_vips(sbrec_lb, - ovn_northd_lb_get_vips(lb_dps->lb)); - sbrec_load_balancer_set_protocol(sbrec_lb, lb_dps->lb->nlb->protocol); -- sbrec_load_balancer_set_datapath_group(sbrec_lb, lb_dpg->dp_group); -+ -+ if (chassis_features->ls_dpg_column) { -+ sbrec_load_balancer_set_ls_datapath_group( -+ sbrec_lb, lb_dpg ? lb_dpg->dp_group : NULL -+ ); -+ sbrec_load_balancer_set_datapath_group(sbrec_lb, NULL); -+ } else { -+ /* datapath_group column is deprecated. */ -+ sbrec_load_balancer_set_ls_datapath_group(sbrec_lb, NULL); -+ sbrec_load_balancer_set_datapath_group( -+ sbrec_lb, lb_dpg ? lb_dpg->dp_group : NULL -+ ); -+ } -+ -+ sbrec_load_balancer_set_lr_datapath_group( -+ sbrec_lb, lb_lr_dpg ? lb_lr_dpg->dp_group : NULL -+ ); - sbrec_load_balancer_set_options(sbrec_lb, &options); - /* Clearing 'datapaths' column, since 'dp_group' is in use. */ - sbrec_load_balancer_set_datapaths(sbrec_lb, NULL, 0); -@@ -4636,11 +4704,17 @@ sync_lbs(struct ovsdb_idl_txn *ovnsb_txn, - } - - struct ovn_dp_group *dpg; -- HMAP_FOR_EACH_POP (dpg, node, &dp_groups) { -+ HMAP_FOR_EACH_POP (dpg, node, &ls_dp_groups) { - bitmap_free(dpg->bitmap); - free(dpg); - } -- hmap_destroy(&dp_groups); -+ hmap_destroy(&ls_dp_groups); -+ -+ HMAP_FOR_EACH_POP (dpg, node, &lr_dp_groups) { -+ bitmap_free(dpg->bitmap); -+ free(dpg); -+ } -+ hmap_destroy(&lr_dp_groups); - - struct sb_lb *sb_lb; - HMAP_FOR_EACH_POP (sb_lb, hmap_node, &sb_lbs) { -@@ -4655,12 +4729,39 @@ sync_lbs(struct ovsdb_idl_txn *ovnsb_txn, - HMAP_FOR_EACH (od, key_node, &ls_datapaths->datapaths) { - ovs_assert(od->nbs); - -+ if (od->sb->n_load_balancers) { -+ sbrec_datapath_binding_set_load_balancers(od->sb, NULL, 0); -+ } -+ } -+ HMAP_FOR_EACH (od, key_node, &lr_datapaths->datapaths) { -+ ovs_assert(od->nbr); -+ - if (od->sb->n_load_balancers) { - sbrec_datapath_binding_set_load_balancers(od->sb, NULL, 0); - } - } - } - -+bool -+check_sb_lb_duplicates(const struct sbrec_load_balancer_table *table) -+{ -+ struct sset existing_nb_lb_uuids = -+ SSET_INITIALIZER(&existing_nb_lb_uuids); -+ const struct sbrec_load_balancer *sbrec_lb; -+ bool duplicates = false; -+ -+ SBREC_LOAD_BALANCER_TABLE_FOR_EACH (sbrec_lb, table) { -+ const char *nb_lb_uuid = smap_get(&sbrec_lb->external_ids, "lb_id"); -+ if (nb_lb_uuid && !sset_add(&existing_nb_lb_uuids, nb_lb_uuid)) { -+ duplicates = true; -+ break; -+ } -+ } -+ -+ sset_destroy(&existing_nb_lb_uuids); -+ return duplicates; -+} -+ - /* Syncs the SB port binding for the ovn_port 'op'. Caller should make sure - * that the OVN SB IDL txn is not NULL. Presently it only syncs the nat - * column of port binding corresponding to the 'op->nbsp' */ -@@ -5089,23 +5190,21 @@ lsp_can_be_inc_processed(const struct nbrec_logical_switch_port *nbsp) - } - - static bool --ls_port_has_changed(const struct nbrec_logical_switch_port *old, -- const struct nbrec_logical_switch_port *new) -+ls_port_has_changed(const struct nbrec_logical_switch_port *new) - { -- if (old != new) { -- return true; -- } - /* XXX: Need a better OVSDB IDL interface for this check. */ - return (nbrec_logical_switch_port_row_get_seqno(new, - OVSDB_IDL_CHANGE_MODIFY) > 0); - } - - static struct ovn_port * --ovn_port_find_in_datapath(struct ovn_datapath *od, const char *name) -+ovn_port_find_in_datapath(struct ovn_datapath *od, -+ const struct nbrec_logical_switch_port *nbsp) - { - struct ovn_port *op; -- HMAP_FOR_EACH_WITH_HASH (op, dp_node, hash_string(name, 0), &od->ports) { -- if (!strcmp(op->key, name)) { -+ HMAP_FOR_EACH_WITH_HASH (op, dp_node, hash_string(nbsp->name, 0), -+ &od->ports) { -+ if (!strcmp(op->key, nbsp->name) && op->nbsp == nbsp) { - return op; - } - } -@@ -5290,7 +5389,7 @@ ls_handle_lsp_changes(struct ovsdb_idl_txn *ovnsb_idl_txn, - /* Compare the individual ports in the old and new Logical Switches */ - for (size_t j = 0; j < changed_ls->n_ports; ++j) { - struct nbrec_logical_switch_port *new_nbsp = changed_ls->ports[j]; -- op = ovn_port_find_in_datapath(od, new_nbsp->name); -+ op = ovn_port_find_in_datapath(od, new_nbsp); - - if (!op) { - if (!lsp_can_be_inc_processed(new_nbsp)) { -@@ -5307,7 +5406,7 @@ ls_handle_lsp_changes(struct ovsdb_idl_txn *ovnsb_idl_txn, - } - ovs_list_push_back(&ls_change->added_ports, - &op->list); -- } else if (ls_port_has_changed(op->nbsp, new_nbsp)) { -+ } else if (ls_port_has_changed(new_nbsp)) { - /* Existing port updated */ - bool temp = false; - if (lsp_is_type_changed(op->sb, new_nbsp, &temp) || -@@ -5580,9 +5679,9 @@ northd_handle_sb_port_binding_changes( - * notification of that transaction, and we can ignore in this - * case. Fallback to recompute otherwise, to avoid dangling - * sb idl pointers and other unexpected behavior. */ -- if (op) { -- VLOG_WARN_RL(&rl, "A port-binding for %s is deleted but the " -- "LSP still exists.", pb->logical_port); -+ if (op && op->sb == pb) { -+ VLOG_WARN_RL(&rl, "A port-binding for %s is deleted but " -+ "the LSP still exists.", pb->logical_port); - return false; - } - } else { -@@ -6954,6 +7053,9 @@ build_lswitch_learn_fdb_op( - ds_clear(match); - ds_clear(actions); - ds_put_format(match, "inport == %s", op->json_key); -+ if (lsp_is_localnet(op->nbsp)) { -+ ds_put_cstr(actions, "flags.localnet = 1; "); -+ } - ds_put_format(actions, REGBIT_LKUP_FDB - " = lookup_fdb(inport, eth.src); next;"); - ovn_lflow_add_with_lport_and_hint(lflows, op->od, -@@ -8291,12 +8393,12 @@ build_lb_rules_pre_stateful(struct hmap *lflows, - * - * - load balancing: - * table=lr_in_dnat, priority=150 -- * match=(REGBIT_KNOWN_LB_SESSION == 1 && ct.new && ip4 -+ * match=(REGBIT_KNOWN_LB_SESSION == 1 && ct.new && ip4.dst == V - * && REG_LB_AFF_BACKEND_IP4 == B1 && REG_LB_AFF_MATCH_PORT == BP1) - * action=(REG_NEXT_HOP_IPV4 = V; lb_action; - * ct_lb_mark(backends=B1:BP1; ct_flag);) - * table=lr_in_dnat, priority=150 -- * match=(REGBIT_KNOWN_LB_SESSION == 1 && ct.new && ip4 -+ * match=(REGBIT_KNOWN_LB_SESSION == 1 && ct.new && ip4.dst == V - * && REG_LB_AFF_BACKEND_IP4 == B2 && REG_LB_AFF_MATCH_PORT == BP2) - * action=(REG_NEXT_HOP_IPV4 = V; lb_action; - * ct_lb_mark(backends=B2:BP2; ct_flag);) -@@ -8395,7 +8497,8 @@ build_lb_affinity_lr_flows(struct hmap *lflows, const struct ovn_northd_lb *lb, - - /* Prepare common part of affinity match. */ - ds_put_format(&aff_match, REGBIT_KNOWN_LB_SESSION" == 1 && " -- "ct.new && %s && %s == ", ip_match, reg_backend); -+ "ct.new && %s.dst == %s && %s == ", ip_match, -+ lb_vip->vip_str, reg_backend); - - /* Store the common part length. */ - size_t aff_action_len = aff_action.length; -@@ -8474,13 +8577,13 @@ build_lb_affinity_lr_flows(struct hmap *lflows, const struct ovn_northd_lb *lb, - * - * - load balancing: - * table=ls_in_lb, priority=150 -- * match=(REGBIT_KNOWN_LB_SESSION == 1 && ct.new && ip4 -+ * match=(REGBIT_KNOWN_LB_SESSION == 1 && ct.new && ip4.dst == V - * && REG_LB_AFF_BACKEND_IP4 == B1 && REG_LB_AFF_MATCH_PORT == BP1) - * action=(REGBIT_CONNTRACK_COMMIT = 0; - * REG_ORIG_DIP_IPV4 = V; REG_ORIG_TP_DPORT = VP; - * ct_lb_mark(backends=B1:BP1);) - * table=ls_in_lb, priority=150 -- * match=(REGBIT_KNOWN_LB_SESSION == 1 && ct.new && ip4 -+ * match=(REGBIT_KNOWN_LB_SESSION == 1 && ct.new && ip4.dst == V - * && REG_LB_AFF_BACKEND_IP4 == B2 && REG_LB_AFF_MATCH_PORT == BP2) - * action=(REGBIT_CONNTRACK_COMMIT = 0; - * REG_ORIG_DIP_IPV4 = V; -@@ -8583,7 +8686,8 @@ build_lb_affinity_ls_flows(struct hmap *lflows, - - /* Prepare common part of affinity match. */ - ds_put_format(&aff_match, REGBIT_KNOWN_LB_SESSION" == 1 && " -- "ct.new && %s && %s == ", ip_match, reg_backend); -+ "ct.new && %s.dst == %s && %s == ", ip_match, -+ lb_vip->vip_str, reg_backend); - - /* Store the common part length. */ - size_t aff_action_len = aff_action.length; -@@ -9307,6 +9411,37 @@ build_lswitch_rport_arp_req_flows(struct ovn_port *op, - } - } - -+ struct shash_node *snat_snode; -+ SHASH_FOR_EACH (snat_snode, &op->od->snat_ips) { -+ struct ovn_snat_ip *snat_ip = snat_snode->data; -+ -+ if (ovs_list_is_empty(&snat_ip->snat_entries)) { -+ continue; -+ } -+ -+ struct ovn_nat *nat_entry = -+ CONTAINER_OF(ovs_list_front(&snat_ip->snat_entries), -+ struct ovn_nat, ext_addr_list_node); -+ const struct nbrec_nat *nat = nat_entry->nb; -+ -+ /* Check if the ovn port has a network configured on which we could -+ * expect ARP requests/NS for the SNAT external_ip. -+ */ -+ if (nat_entry_is_v6(nat_entry)) { -+ if (!sset_contains(&op->od->lb_ips->ips_v6, nat->external_ip)) { -+ build_lswitch_rport_arp_req_flow( -+ nat->external_ip, AF_INET6, sw_op, sw_od, 80, lflows, -+ stage_hint); -+ } -+ } else { -+ if (!sset_contains(&op->od->lb_ips->ips_v4, nat->external_ip)) { -+ build_lswitch_rport_arp_req_flow( -+ nat->external_ip, AF_INET, sw_op, sw_od, 80, lflows, -+ stage_hint); -+ } -+ } -+ } -+ - for (size_t i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { - build_lswitch_rport_arp_req_flow( - op->lrp_networks.ipv4_addrs[i].addr_s, AF_INET, sw_op, sw_od, 80, -@@ -9651,6 +9786,13 @@ build_lswitch_lflows_admission_control(struct ovn_datapath *od, - struct hmap *lflows) - { - ovs_assert(od->nbs); -+ -+ /* Default action for recirculated ICMP error 'packet too big'. */ -+ ovn_lflow_add(lflows, od, S_SWITCH_IN_CHECK_PORT_SEC, 110, -+ "((ip4 && icmp4.type == 3 && icmp4.code == 4) ||" -+ " (ip6 && icmp6.type == 2 && icmp6.code == 0)) &&" -+ " flags.tunnel_rx == 1", debug_drop_action()); -+ - /* Logical VLANs not supported. */ - if (!is_vlan_transparent(od)) { - /* Block logical VLANs. */ -@@ -11385,7 +11527,6 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows, - struct ds *route_match) - { - const struct nbrec_logical_router_static_route *st_route = route->route; -- struct ds base_match = DS_EMPTY_INITIALIZER; - struct ds match = DS_EMPTY_INITIALIZER; - struct ds actions = DS_EMPTY_INITIALIZER; - struct ds ecmp_reply = DS_EMPTY_INITIALIZER; -@@ -11397,14 +11538,14 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows, - /* If symmetric ECMP replies are enabled, then packets that arrive over - * an ECMP route need to go through conntrack. - */ -- ds_put_format(&base_match, "inport == %s && ip%s.%s == %s", -+ ds_put_format(&match, "inport == %s && ip%s.%s == %s", - out_port->json_key, - IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "4" : "6", - route->is_src_route ? "dst" : "src", - cidr); - free(cidr); - ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DEFRAG, 100, -- ds_cstr(&base_match), "ct_next;", -+ ds_cstr(&match), "ct_next;", - &st_route->header_); - - /* And packets that go out over an ECMP route need conntrack */ -@@ -11418,73 +11559,7 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows, - * NOTE: we purposely are not clearing match before this - * ds_put_cstr() call. The previous contents are needed. - */ -- ds_put_format(&match, "%s && (ct.new && !ct.est) && tcp", -- ds_cstr(&base_match)); -- ds_put_format(&actions, -- "ct_commit { ct_label.ecmp_reply_eth = eth.src; " -- " %s = %" PRId64 ";}; " -- "next;", -- ct_ecmp_reply_port_match, out_port->sb->tunnel_key); -- ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100, -- ds_cstr(&match), ds_cstr(&actions), -- &st_route->header_); -- ds_clear(&match); -- ds_put_format(&match, "%s && (ct.new && !ct.est) && udp", -- ds_cstr(&base_match)); -- ds_clear(&actions); -- ds_put_format(&actions, -- "ct_commit { ct_label.ecmp_reply_eth = eth.src; " -- " %s = %" PRId64 ";}; " -- "next;", -- ct_ecmp_reply_port_match, out_port->sb->tunnel_key); -- ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100, -- ds_cstr(&match), ds_cstr(&actions), -- &st_route->header_); -- ds_clear(&match); -- ds_put_format(&match, "%s && (ct.new && !ct.est) && sctp", -- ds_cstr(&base_match)); -- ds_clear(&actions); -- ds_put_format(&actions, -- "ct_commit { ct_label.ecmp_reply_eth = eth.src; " -- " %s = %" PRId64 ";}; " -- "next;", -- ct_ecmp_reply_port_match, out_port->sb->tunnel_key); -- ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100, -- ds_cstr(&match), ds_cstr(&actions), -- &st_route->header_); -- -- ds_clear(&match); -- ds_put_format(&match, -- "%s && (!ct.rpl && ct.est) && tcp", -- ds_cstr(&base_match)); -- ds_clear(&actions); -- ds_put_format(&actions, -- "ct_commit { ct_label.ecmp_reply_eth = eth.src; " -- " %s = %" PRId64 ";}; " -- "next;", -- ct_ecmp_reply_port_match, out_port->sb->tunnel_key); -- ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100, -- ds_cstr(&match), ds_cstr(&actions), -- &st_route->header_); -- -- ds_clear(&match); -- ds_put_format(&match, -- "%s && (!ct.rpl && ct.est) && udp", -- ds_cstr(&base_match)); -- ds_clear(&actions); -- ds_put_format(&actions, -- "ct_commit { ct_label.ecmp_reply_eth = eth.src; " -- " %s = %" PRId64 ";}; " -- "next;", -- ct_ecmp_reply_port_match, out_port->sb->tunnel_key); -- ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_ECMP_STATEFUL, 100, -- ds_cstr(&match), ds_cstr(&actions), -- &st_route->header_); -- ds_clear(&match); -- ds_put_format(&match, -- "%s && (!ct.rpl && ct.est) && sctp", -- ds_cstr(&base_match)); -- ds_clear(&actions); -+ ds_put_cstr(&match, " && !ct.rpl && (ct.new || ct.est)"); - ds_put_format(&actions, - "ct_commit { ct_label.ecmp_reply_eth = eth.src; " - " %s = %" PRId64 ";}; " -@@ -11534,7 +11609,6 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows, - 200, ds_cstr(&ecmp_reply), - action, &st_route->header_); - -- ds_destroy(&base_match); - ds_destroy(&match); - ds_destroy(&actions); - ds_destroy(&ecmp_reply); -@@ -11950,7 +12024,6 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, - struct ds skip_snat_act = DS_EMPTY_INITIALIZER; - struct ds force_snat_act = DS_EMPTY_INITIALIZER; - struct ds undnat_match = DS_EMPTY_INITIALIZER; -- struct ds unsnat_match = DS_EMPTY_INITIALIZER; - struct ds gw_redir_action = DS_EMPTY_INITIALIZER; - - ds_clear(match); -@@ -11996,13 +12069,6 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, - /* Remove the trailing " || ". */ - ds_truncate(&undnat_match, undnat_match.length - 4); - -- ds_put_format(&unsnat_match, "%s && %s.dst == %s && %s", -- ip_match, ip_match, lb_vip->vip_str, lb->proto); -- if (lb_vip->port_str) { -- ds_put_format(&unsnat_match, " && %s.dst == %s", lb->proto, -- lb_vip->port_str); -- } -- - struct lrouter_nat_lb_flows_ctx ctx = { - .lb_vip = lb_vip, - .lb = lb, -@@ -12054,23 +12120,6 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, - if (lb->affinity_timeout) { - bitmap_set1(aff_dp_bitmap[type], index); - } -- -- if (sset_contains(&od->external_ips, lb_vip->vip_str)) { -- /* The load balancer vip is also present in the NAT entries. -- * So add a high priority lflow to advance the the packet -- * destined to the vip (and the vip port if defined) -- * in the S_ROUTER_IN_UNSNAT stage. -- * There seems to be an issue with ovs-vswitchd. When the new -- * connection packet destined for the lb vip is received, -- * it is dnat'ed in the S_ROUTER_IN_DNAT stage in the dnat -- * conntrack zone. For the next packet, if it goes through -- * unsnat stage, the conntrack flags are not set properly, and -- * it doesn't hit the established state flows in -- * S_ROUTER_IN_DNAT stage. */ -- ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_UNSNAT, 120, -- ds_cstr(&unsnat_match), "next;", -- &lb->nlb->header_); -- } - } - - for (size_t type = 0; type < LROUTER_NAT_LB_FLOW_MAX; type++) { -@@ -12081,7 +12130,6 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip, - lr_datapaths); - } - -- ds_destroy(&unsnat_match); - ds_destroy(&undnat_match); - ds_destroy(&skip_snat_act); - ds_destroy(&force_snat_act); -@@ -12690,6 +12738,72 @@ build_lrouter_force_snat_flows(struct hmap *lflows, struct ovn_datapath *od, - ds_destroy(&actions); - } - -+/* Following flows are used to manage traffic redirected by the kernel -+ * (e.g. ICMP errors packets) that enter the cluster from the geneve ports -+ */ -+static void -+build_lrouter_icmp_packet_toobig_admin_flows( -+ struct ovn_port *op, struct hmap *lflows, -+ struct ds *match, struct ds *actions) -+{ -+ ovs_assert(op->nbrp); -+ -+ if (!is_l3dgw_port(op)) { -+ return; -+ } -+ -+ ds_clear(match); -+ ds_put_format(match, -+ "((ip4 && icmp4.type == 3 && icmp4.code == 4) ||" -+ " (ip6 && icmp6.type == 2 && icmp6.code == 0)) &&" -+ " eth.dst == %s && !is_chassis_resident(%s) &&" -+ " flags.tunnel_rx == 1", -+ op->nbrp->mac, op->cr_port->json_key); -+ ds_clear(actions); -+ ds_put_format(actions, "outport <-> inport; inport = %s; next;", -+ op->json_key); -+ ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ADMISSION, 120, -+ ds_cstr(match), ds_cstr(actions)); -+} -+ -+static void -+build_lswitch_icmp_packet_toobig_admin_flows( -+ struct ovn_port *op, struct hmap *lflows, -+ struct ds *match, struct ds *actions) -+{ -+ ovs_assert(op->nbsp); -+ -+ if (!lsp_is_router(op->nbsp)) { -+ return; -+ } -+ -+ struct ovn_port *peer = op->peer; -+ if (!peer) { -+ return; -+ } -+ -+ ds_clear(match); -+ if (peer->od->is_gw_router) { -+ ds_put_format(match, -+ "((ip4 && icmp4.type == 3 && icmp4.code == 4) ||" -+ " (ip6 && icmp6.type == 2 && icmp6.code == 0)) && " -+ "eth.src == %s && outport == %s && flags.tunnel_rx == 1", -+ peer->nbrp->mac, op->json_key); -+ } else { -+ ds_put_format(match, -+ "((ip4 && icmp4.type == 3 && icmp4.code == 4) ||" -+ " (ip6 && icmp6.type == 2 && icmp6.code == 0)) && " -+ "eth.dst == %s && flags.tunnel_rx == 1", -+ peer->nbrp->mac); -+ } -+ ds_clear(actions); -+ ds_put_format(actions, -+ "outport <-> inport; next(pipeline=ingress,table=%d);", -+ ovn_stage_get_table(S_SWITCH_IN_L2_LKUP)); -+ ovn_lflow_add(lflows, op->od, S_SWITCH_IN_CHECK_PORT_SEC, 120, -+ ds_cstr(match), ds_cstr(actions)); -+} -+ - static void - build_lrouter_force_snat_flows_op(struct ovn_port *op, - struct hmap *lflows, -@@ -12822,6 +12936,13 @@ build_adm_ctrl_flows_for_lrouter( - struct ovn_datapath *od, struct hmap *lflows) - { - ovs_assert(od->nbr); -+ -+ /* Default action for recirculated ICMP error 'packet too big'. */ -+ ovn_lflow_add(lflows, od, S_ROUTER_IN_ADMISSION, 110, -+ "((ip4 && icmp4.type == 3 && icmp4.code == 4) ||" -+ " (ip6 && icmp6.type == 2 && icmp6.code == 0)) &&" -+ " flags.tunnel_rx == 1", debug_drop_action()); -+ - /* Logical VLANs not supported. - * Broadcast/multicast source address is invalid. */ - ovn_lflow_add(lflows, od, S_ROUTER_IN_ADMISSION, 100, -@@ -13047,9 +13168,9 @@ build_neigh_learning_flows_for_lrouter( - * address, the all-nodes multicast address. */ - ds_clear(actions); - ds_put_format(actions, REGBIT_LOOKUP_NEIGHBOR_RESULT -- " = lookup_nd(inport, ip6.src, nd.tll); " -+ " = lookup_nd(inport, nd.target, nd.tll); " - REGBIT_LOOKUP_NEIGHBOR_IP_RESULT -- " = lookup_nd_ip(inport, ip6.src); next;"); -+ " = lookup_nd_ip(inport, nd.target); next;"); - ovn_lflow_add(lflows, od, S_ROUTER_IN_LOOKUP_NEIGHBOR, 110, - "nd_na && ip6.src == fe80::/10 && ip6.dst == ff00::/8", - ds_cstr(actions)); -@@ -13885,82 +14006,103 @@ build_arp_resolve_flows_for_lsp( - } - } - -+#define ICMP4_NEED_FRAG_FORMAT \ -+ "icmp4_error {" \ -+ "%s" \ -+ REGBIT_EGRESS_LOOPBACK" = 1; " \ -+ REGBIT_PKT_LARGER" = 0; " \ -+ "eth.dst = %s; " \ -+ "ip4.dst = ip4.src; " \ -+ "ip4.src = %s; " \ -+ "ip.ttl = 255; " \ -+ "icmp4.type = 3; /* Destination Unreachable. */ " \ -+ "icmp4.code = 4; /* Frag Needed and DF was Set. */ " \ -+ "icmp4.frag_mtu = %d; " \ -+ "next(pipeline=ingress, table=%d); };" \ -+ -+#define ICMP6_NEED_FRAG_FORMAT \ -+ "icmp6_error {" \ -+ "%s" \ -+ REGBIT_EGRESS_LOOPBACK" = 1; " \ -+ REGBIT_PKT_LARGER" = 0; " \ -+ "eth.dst = %s; " \ -+ "ip6.dst = ip6.src; " \ -+ "ip6.src = %s; " \ -+ "ip.ttl = 255; " \ -+ "icmp6.type = 2; /* Packet Too Big. */ " \ -+ "icmp6.code = 0; " \ -+ "icmp6.frag_mtu = %d; " \ -+ "next(pipeline=ingress, table=%d); };" -+ -+static void -+create_icmp_need_frag_lflow(const struct ovn_port *op, int mtu, -+ struct ds *actions, struct ds *match, -+ const char *meter, struct hmap *lflows, -+ enum ovn_stage stage, uint16_t priority, -+ bool is_ipv6, const char *extra_match, -+ const char *extra_action) -+{ -+ if ((is_ipv6 && !op->lrp_networks.ipv6_addrs) || -+ (!is_ipv6 && !op->lrp_networks.ipv4_addrs)) { -+ return; -+ } -+ -+ const char *ip = is_ipv6 -+ ? op->lrp_networks.ipv6_addrs[0].addr_s -+ : op->lrp_networks.ipv4_addrs[0].addr_s; -+ size_t match_len = match->length; -+ -+ ds_put_format(match, " && ip%c && "REGBIT_PKT_LARGER -+ " && "REGBIT_EGRESS_LOOPBACK" == 0", is_ipv6 ? '6' : '4'); -+ -+ if (*extra_match) { -+ ds_put_format(match, " && %s", extra_match); -+ } -+ -+ ds_clear(actions); -+ ds_put_format(actions, -+ is_ipv6 ? ICMP6_NEED_FRAG_FORMAT : ICMP4_NEED_FRAG_FORMAT, -+ extra_action, op->lrp_networks.ea_s, ip, -+ mtu, ovn_stage_get_table(S_ROUTER_IN_ADMISSION)); -+ -+ ovn_lflow_add_with_hint__(lflows, op->od, stage, priority, -+ ds_cstr(match), ds_cstr(actions), -+ NULL, meter, &op->nbrp->header_); -+ -+ ds_truncate(match, match_len); -+} -+ - static void - build_icmperr_pkt_big_flows(struct ovn_port *op, int mtu, struct hmap *lflows, - const struct shash *meter_groups, struct ds *match, - struct ds *actions, enum ovn_stage stage, - struct ovn_port *outport) - { -- char *outport_match = outport ? xasprintf("outport == %s && ", -- outport->json_key) -- : NULL; -- -- if (op->lrp_networks.ipv4_addrs) { -- ds_clear(match); -- ds_put_format(match, "inport == %s && %sip4 && "REGBIT_PKT_LARGER -- " && "REGBIT_EGRESS_LOOPBACK" == 0", op->json_key, -- outport ? outport_match : ""); -+ const char *ipv4_meter = copp_meter_get(COPP_ICMP4_ERR, op->od->nbr->copp, -+ meter_groups); -+ const char *ipv6_meter = copp_meter_get(COPP_ICMP6_ERR, op->od->nbr->copp, -+ meter_groups); - -- ds_clear(actions); -- /* Set icmp4.frag_mtu to gw_mtu */ -- ds_put_format(actions, -- "icmp4_error {" -- REGBIT_EGRESS_LOOPBACK" = 1; " -- REGBIT_PKT_LARGER" = 0; " -- "eth.dst = %s; " -- "ip4.dst = ip4.src; " -- "ip4.src = %s; " -- "ip.ttl = 255; " -- "icmp4.type = 3; /* Destination Unreachable. */ " -- "icmp4.code = 4; /* Frag Needed and DF was Set. */ " -- "icmp4.frag_mtu = %d; " -- "next(pipeline=ingress, table=%d); };", -- op->lrp_networks.ea_s, -- op->lrp_networks.ipv4_addrs[0].addr_s, -- mtu, ovn_stage_get_table(S_ROUTER_IN_ADMISSION)); -- ovn_lflow_add_with_hint__(lflows, op->od, stage, 150, -- ds_cstr(match), ds_cstr(actions), -- NULL, -- copp_meter_get( -- COPP_ICMP4_ERR, -- op->od->nbr->copp, -- meter_groups), -- &op->nbrp->header_); -- } -+ ds_clear(match); -+ ds_put_format(match, "inport == %s", op->json_key); - -- if (op->lrp_networks.ipv6_addrs) { -- ds_clear(match); -- ds_put_format(match, "inport == %s && %sip6 && "REGBIT_PKT_LARGER -- " && "REGBIT_EGRESS_LOOPBACK" == 0", op->json_key, -- outport ? outport_match : ""); -+ if (outport) { -+ ds_put_format(match, " && outport == %s", outport->json_key); - -- ds_clear(actions); -- /* Set icmp6.frag_mtu to gw_mtu */ -- ds_put_format(actions, -- "icmp6_error {" -- REGBIT_EGRESS_LOOPBACK" = 1; " -- REGBIT_PKT_LARGER" = 0; " -- "eth.dst = %s; " -- "ip6.dst = ip6.src; " -- "ip6.src = %s; " -- "ip.ttl = 255; " -- "icmp6.type = 2; /* Packet Too Big. */ " -- "icmp6.code = 0; " -- "icmp6.frag_mtu = %d; " -- "next(pipeline=ingress, table=%d); };", -- op->lrp_networks.ea_s, -- op->lrp_networks.ipv6_addrs[0].addr_s, -- mtu, ovn_stage_get_table(S_ROUTER_IN_ADMISSION)); -- ovn_lflow_add_with_hint__(lflows, op->od, stage, 150, -- ds_cstr(match), ds_cstr(actions), -- NULL, -- copp_meter_get( -- COPP_ICMP6_ERR, -- op->od->nbr->copp, -- meter_groups), -- &op->nbrp->header_); -+ create_icmp_need_frag_lflow(op, mtu, actions, match, ipv4_meter, -+ lflows, stage, 160, false, -+ "ct.trk && ct.rpl && ct.dnat", -+ "flags.icmp_snat = 1; "); -+ create_icmp_need_frag_lflow(op, mtu, actions, match, ipv6_meter, -+ lflows, stage, 160, true, -+ "ct.trk && ct.rpl && ct.dnat", -+ "flags.icmp_snat = 1; "); - } -- free(outport_match); -+ -+ create_icmp_need_frag_lflow(op, mtu, actions, match, ipv4_meter, lflows, -+ stage, 150, false, "", ""); -+ create_icmp_need_frag_lflow(op, mtu, actions, match, ipv6_meter, lflows, -+ stage, 150, true, "", ""); - } - - static void -@@ -13968,8 +14110,8 @@ build_check_pkt_len_flows_for_lrp(struct ovn_port *op, - struct hmap *lflows, - const struct hmap *lr_ports, - const struct shash *meter_groups, -- struct ds *match, -- struct ds *actions) -+ struct ds *match, struct ds *actions, -+ const struct chassis_features *features) - { - int gw_mtu = smap_get_int(&op->nbrp->options, "gateway_mtu", 0); - if (gw_mtu <= 0) { -@@ -13998,6 +14140,12 @@ build_check_pkt_len_flows_for_lrp(struct ovn_port *op, - match, actions, S_ROUTER_IN_LARGER_PKTS, - op); - } -+ -+ if (features->ct_commit_nat_v2) { -+ ovn_lflow_add_with_hint(lflows, op->od, S_ROUTER_OUT_POST_SNAT, 100, -+ "icmp && flags.icmp_snat == 1", -+ "ct_commit_nat(snat);", &op->nbrp->header_); -+ } - } - - /* Local router ingress table CHK_PKT_LEN: Check packet length. -@@ -14018,7 +14166,8 @@ build_check_pkt_len_flows_for_lrouter( - struct ovn_datapath *od, struct hmap *lflows, - const struct hmap *lr_ports, - struct ds *match, struct ds *actions, -- const struct shash *meter_groups) -+ const struct shash *meter_groups, -+ const struct chassis_features *features) - { - ovs_assert(od->nbr); - -@@ -14035,7 +14184,7 @@ build_check_pkt_len_flows_for_lrouter( - continue; - } - build_check_pkt_len_flows_for_lrp(rp, lflows, lr_ports, meter_groups, -- match, actions); -+ match, actions, features); - } - } - -@@ -15217,6 +15366,7 @@ build_lrouter_out_snat_in_czone_flow(struct hmap *lflows, - ds_put_format(&zone_actions, "eth.src = "ETH_ADDR_FMT"; ", - ETH_ADDR_ARGS(mac)); - } -+ ds_put_format(match, " && (!ct.trk || !ct.rpl)"); - - ds_put_cstr(&zone_actions, REGBIT_DST_NAT_IP_LOCAL" = 0; "); - -@@ -15275,10 +15425,8 @@ build_lrouter_out_snat_flow(struct hmap *lflows, struct ovn_datapath *od, - ds_put_format(actions, "eth.src = "ETH_ADDR_FMT"; ", - ETH_ADDR_ARGS(mac)); - } -- } else { -- /* Gateway router. */ -- ds_put_cstr(match, " && (!ct.trk || !ct.rpl)"); - } -+ ds_put_cstr(match, " && (!ct.trk || !ct.rpl)"); - - ds_put_format(actions, "ct_snat(%s", nat->external_ip); - if (nat->external_port_range[0]) { -@@ -15704,12 +15852,7 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od, struct hmap *lflows, - l3dgw_port, stateless); - - /* ARP resolve for NAT IPs. */ -- if (od->is_gw_router) { -- /* Add the NAT external_ip to the nat_entries for -- * gateway routers. This is required for adding load balancer -- * flows.*/ -- sset_add(&nat_entries, nat->external_ip); -- } else { -+ if (!od->is_gw_router) { - if (!sset_contains(&nat_entries, nat->external_ip)) { - /* Drop packets coming in from external that still has - * destination IP equals to the NAT external IP, to avoid loop. -@@ -16006,7 +16149,7 @@ build_lswitch_and_lrouter_iterate_by_lr(struct ovn_datapath *od, - build_arp_resolve_flows_for_lrouter(od, lsi->lflows); - build_check_pkt_len_flows_for_lrouter(od, lsi->lflows, lsi->lr_ports, - &lsi->match, &lsi->actions, -- lsi->meter_groups); -+ lsi->meter_groups, lsi->features); - build_gateway_redirect_flows_for_lrouter(od, lsi->lflows, &lsi->match, - &lsi->actions); - build_arp_request_flows_for_lrouter(od, lsi->lflows, &lsi->match, -@@ -16044,6 +16187,7 @@ build_lswitch_and_lrouter_iterate_by_lsp(struct ovn_port *op, - build_lswitch_dhcp_options_and_response(op, lflows, meter_groups); - build_lswitch_external_port(op, lflows); - build_lswitch_ip_unicast_lookup(op, lflows, actions, match); -+ build_lswitch_icmp_packet_toobig_admin_flows(op, lflows, match, actions); - - /* Build Logical Router Flows. */ - build_ip_routing_flows_for_router_type_lsp(op, lr_ports, lflows); -@@ -16080,6 +16224,8 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct ovn_port *op, - &lsi->match, &lsi->actions, lsi->meter_groups); - build_lrouter_force_snat_flows_op(op, lsi->lflows, &lsi->match, - &lsi->actions); -+ build_lrouter_icmp_packet_toobig_admin_flows(op, lsi->lflows, &lsi->match, -+ &lsi->actions); - } - - static void * -@@ -17655,6 +17801,8 @@ northd_init(struct northd_data *data) - .mac_binding_timestamp = true, - .ct_lb_related = true, - .fdb_timestamp = true, -+ .ls_dpg_column = true, -+ .ct_commit_nat_v2 = true, - }; - data->ovn_internal_version_changed = false; - sset_init(&data->svc_monitor_lsps); -@@ -18051,13 +18199,15 @@ static void - handle_cr_port_binding_changes(const struct sbrec_port_binding *sb, - struct ovn_port *orp) - { -+ const struct nbrec_logical_router_port *nbrec_lrp = orp->l3dgw_port->nbrp; -+ - if (sb->chassis) { -- nbrec_logical_router_port_update_status_setkey( -- orp->l3dgw_port->nbrp, "hosting-chassis", -- sb->chassis->name); -- } else { -- nbrec_logical_router_port_update_status_delkey( -- orp->l3dgw_port->nbrp, "hosting-chassis"); -+ nbrec_logical_router_port_update_status_setkey(nbrec_lrp, -+ "hosting-chassis", -+ sb->chassis->name); -+ } else if (smap_get(&nbrec_lrp->status, "hosting-chassis")) { -+ nbrec_logical_router_port_update_status_delkey(nbrec_lrp, -+ "hosting-chassis"); - } - } - -diff --git a/northd/northd.h b/northd/northd.h -index 4d030b10d..5bde4bb16 100644 ---- a/northd/northd.h -+++ b/northd/northd.h -@@ -70,6 +70,8 @@ struct chassis_features { - bool mac_binding_timestamp; - bool ct_lb_related; - bool fdb_timestamp; -+ bool ls_dpg_column; -+ bool ct_commit_nat_v2; - }; - - /* A collection of datapaths. E.g. all logical switch datapaths, or all -@@ -365,7 +367,11 @@ const char *northd_get_svc_monitor_mac(void); - const struct ovn_datapath *northd_get_datapath_for_port( - const struct hmap *ls_ports, const char *port_name); - void sync_lbs(struct ovsdb_idl_txn *, const struct sbrec_load_balancer_table *, -- struct ovn_datapaths *ls_datapaths, struct hmap *lbs); -+ struct ovn_datapaths *ls_datapaths, -+ struct ovn_datapaths *lr_datapaths, -+ struct hmap *lbs, -+ struct chassis_features *chassis_features); -+bool check_sb_lb_duplicates(const struct sbrec_load_balancer_table *); - - void sync_pbs(struct ovsdb_idl_txn *, struct hmap *ls_ports); - bool sync_pbs_for_northd_ls_changes(struct tracked_ls_changes *); -diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml -index df8ed6750..e6970d6b3 100644 ---- a/northd/ovn-northd.8.xml -+++ b/northd/ovn-northd.8.xml -@@ -341,7 +341,7 @@ -

  • - For each (enabled) vtep logical port, a priority 70 flow is added which - matches on all packets and applies the action -- next(pipeline=ingress, table=S_SWITCH_IN_L2_LKUP) = 1; -+ next(pipeline=ingress, table=S_SWITCH_IN_L3_LKUP) = 1; - to skip most stages of ingress pipeline and go directly to ingress L2 - lookup table to determine the output port. Packets from VTEP (RAMP) - switch should not be subjected to any ACL checks. Egress pipeline will -@@ -372,6 +372,30 @@ - -

    Ingress Table 1: Ingress Port Security - Apply

    - -+

    -+ For each logical switch port P of type router connected to a -+ gw router a priority-120 flow that matches 'recirculated' icmp{4,6} error -+ 'packet too big' and eth.src == D && -+ outport == P && flags.tunnel_rx == 1 where -+ D is the peer logical router port RP mac address, -+ swaps inport and outport and applies the action -+ next(pipeline=S_SWITCH_IN_L2_LKUP). -+

    -+ -+

    -+ For each logical switch port P of type router connected to a -+ distributed router a priority-120 flow that matches 'recirculated' -+ icmp{4,6} error 'packet too big' and eth.dst == D -+ && flags.tunnel_rx == 1 where D is the peer -+ logical router port RP mac address, swaps inport and outport -+ and applies the action next(pipeline=S_SWITCH_IN_L2_LKUP). -+

    -+ -+

    -+ This table adds a priority-110 flow that matches 'recirculated' icmp{4,6} -+ error 'packet too big' to drop the packet. -+

    -+ -

    - This table drops the packets if the port security check failed - in the previous stage i.e the register bit -@@ -399,14 +423,16 @@ -

    - This table looks up the MAC learning table of the logical switch - datapath to check if the port-mac pair is present -- or not. MAC is learnt only for logical switch VIF ports whose -- port security is disabled and 'unknown' address set. -+ or not. MAC is learnt for logical switch VIF ports whose -+ port security is disabled and 'unknown' address setn as well as -+ for localnet ports with option localnet_learn_fdb. A localnet -+ port entry does not overwrite a VIF port entry. -

    - -
      -
    • -

      -- For each such logical port p whose port security -+ For each such VIF logical port p whose port security - is disabled and 'unknown' address set following flow - is added. -

      -@@ -420,6 +446,22 @@ -
    -
  • - -+
  • -+

    -+ For each such localnet logical port p following flow -+ is added. -+

    -+ -+
      -+
    • -+ Priority 100 flow with the match -+ inport == p and action -+ flags.localnet = 1; -+ reg0[11] = lookup_fdb(inport, eth.src); next; -+
    • -+
    -+
  • -+ -
  • - One priority-0 fallback flow that matches all packets and advances to - the next table. -@@ -429,17 +471,20 @@ -

    Ingress Table 3: Learn MAC of 'unknown' ports.

    - -

    -- This table learns the MAC addresses seen on the logical ports -- whose port security is disabled and 'unknown' address set -+ This table learns the MAC addresses seen on the VIF logical ports -+ whose port security is disabled and 'unknown' address set as well -+ as on localnet ports with localnet_learn_fdb option set - if the lookup_fdb action returned false in the -- previous table. -+ previous table. For localnet ports (with flags.localnet = 1), -+ lookup_fdb returns true if (port, mac) is found or if a mac -+ is found for a port of type vif. -

    - -
      -
    • -

      -- For each such logical port p whose port security -- is disabled and 'unknown' address set following flow -+ For each such VIF logical port p whose port security is -+ disabled and 'unknown' address set and localnet port following flow - is added. -

      - -@@ -2442,6 +2487,21 @@ output; - (LBs, NAT). -

      - -+

      -+ For each gateway port GW on a distributed logical router -+ a priority-120 flow that matches 'recirculated' icmp{4,6} error -+ 'packet too big' and eth.dst == D && -+ !is_chassis_resident( cr-GW) where D -+ is the gateway port mac address and cr-GW is the chassis -+ resident port of GW, swap inport and outport and stores -+ GW as inport. -+

      -+ -+

      -+ This table adds a priority-110 flow that matches 'recirculated' -+ icmp{4,6} error 'packet too big' to drop the packet. -+

      -+ -

      - For a distributed logical router or for gateway router where - the port is configured with options:gateway_mtu -diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c -index 68fc8836e..9d9a1d720 100644 ---- a/northd/ovn-northd.c -+++ b/northd/ovn-northd.c -@@ -47,7 +47,6 @@ - - VLOG_DEFINE_THIS_MODULE(ovn_northd); - --static unixctl_cb_func ovn_northd_exit; - static unixctl_cb_func ovn_northd_pause; - static unixctl_cb_func ovn_northd_resume; - static unixctl_cb_func ovn_northd_is_paused; -@@ -612,6 +611,14 @@ parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED, - ssl_ca_cert_file = optarg; - break; - -+ case OPT_SSL_PROTOCOLS: -+ stream_ssl_set_protocols(optarg); -+ break; -+ -+ case OPT_SSL_CIPHERS: -+ stream_ssl_set_ciphers(optarg); -+ break; -+ - case 'd': - ovnsb_db = optarg; - break; -@@ -752,7 +759,7 @@ main(int argc, char *argv[]) - int res = EXIT_SUCCESS; - struct unixctl_server *unixctl; - int retval; -- bool exiting; -+ struct ovn_exit_args exit_args = {}; - int n_threads = 1; - struct northd_state state = { - .had_lock = false, -@@ -774,7 +781,8 @@ main(int argc, char *argv[]) - if (retval) { - exit(EXIT_FAILURE); - } -- unixctl_command_register("exit", "", 0, 0, ovn_northd_exit, &exiting); -+ unixctl_command_register("exit", "", 0, 0, ovn_exit_command_callback, -+ &exit_args); - unixctl_command_register("pause", "", 0, 0, ovn_northd_pause, &state); - unixctl_command_register("resume", "", 0, 0, ovn_northd_resume, &state); - unixctl_command_register("is-paused", "", 0, 0, ovn_northd_is_paused, -@@ -868,6 +876,8 @@ main(int argc, char *argv[]) - stopwatch_create(LFLOWS_IGMP_STOPWATCH_NAME, SW_MS); - stopwatch_create(LFLOWS_DP_GROUPS_STOPWATCH_NAME, SW_MS); - stopwatch_create(LFLOWS_TO_SB_STOPWATCH_NAME, SW_MS); -+ stopwatch_create(PORT_GROUP_RUN_STOPWATCH_NAME, SW_MS); -+ stopwatch_create(SYNC_METERS_RUN_STOPWATCH_NAME, SW_MS); - - /* Initialize incremental processing engine for ovn-northd */ - inc_proc_northd_init(&ovnnb_idl_loop, &ovnsb_idl_loop); -@@ -878,11 +888,9 @@ main(int argc, char *argv[]) - run_update_worker_pool(n_threads); - - /* Main loop. */ -- exiting = false; -- - struct northd_engine_context eng_ctx = {}; - -- while (!exiting) { -+ while (!exit_args.exiting) { - update_ssl_config(); - memory_run(); - if (memory_should_report()) { -@@ -1024,7 +1032,7 @@ main(int argc, char *argv[]) - unixctl_server_run(unixctl); - unixctl_server_wait(unixctl); - memory_wait(); -- if (exiting) { -+ if (exit_args.exiting) { - poll_immediate_wake(); - } - -@@ -1057,15 +1065,16 @@ main(int argc, char *argv[]) - stopwatch_stop(NORTHD_LOOP_STOPWATCH_NAME, time_msec()); - poll_block(); - if (should_service_stop()) { -- exiting = true; -+ exit_args.exiting = true; - } - stopwatch_start(NORTHD_LOOP_STOPWATCH_NAME, time_msec()); - } - inc_proc_northd_cleanup(); - -- unixctl_server_destroy(unixctl); - ovsdb_idl_loop_destroy(&ovnnb_idl_loop); - ovsdb_idl_loop_destroy(&ovnsb_idl_loop); -+ ovn_exit_args_finish(&exit_args); -+ unixctl_server_destroy(unixctl); - service_stop(); - run_update_worker_pool(0); - ovsrcu_exit(); -@@ -1073,16 +1082,6 @@ main(int argc, char *argv[]) - exit(res); - } - --static void --ovn_northd_exit(struct unixctl_conn *conn, int argc OVS_UNUSED, -- const char *argv[] OVS_UNUSED, void *exiting_) --{ -- bool *exiting = exiting_; -- *exiting = true; -- -- unixctl_command_reply(conn, NULL); --} -- - static void - ovn_northd_pause(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *state_) -diff --git a/ovn-nb.xml b/ovn-nb.xml -index 9131305ea..f84ad90c4 100644 ---- a/ovn-nb.xml -+++ b/ovn-nb.xml -@@ -1101,7 +1101,7 @@ - - - Optional. VLAN EtherType field value for encapsulating VLAN -- headers. Supported values: 802.11q (default), 802.11ad. -+ headers. Supported values: 802.1q (default), 802.1ad. - - - - Looks up A in fdb table. If an entry is found -- and the the logical port key is P, P, -+ and the logical port key is P, P, - stores 1 in the 1-bit subfield -- R, else 0. -+ R, else 0. If flags.localnet is set -+ then 1 is stored if an entry is found and the -+ logical port key is P or if an entry is found and -+ the entry port type is VIF. -

      - -

      -@@ -4765,8 +4768,7 @@ tcp.flags = RST; - Each row in this table configures monitoring a service for its liveness. - The service can be an IPv4 TCP or UDP - service. ovn-controller periodically sends out service -- monitor packets and updates the status of the service. Service monitoring -- for IPv6 services is not supported. -+ monitor packets and updates the status of the service. -

      - -

      -@@ -4803,7 +4805,7 @@ tcp.flags = RST; - - - -- Source IPv4 address to use in the service monitor packet. -+ Source IPv4 or IPv6 address to use in the service monitor packet. - - - -@@ -4888,10 +4890,22 @@ tcp.flags = RST; - - - -+ Deprecated. The group of datapaths to which this load balancer applies -+ to. This means that the same load balancer applies to all datapaths in -+ a group. -+ -+ -+ - The group of datapaths to which this load balancer applies to. This - means that the same load balancer applies to all datapaths in a group. - - -+ -+ The group of logical router datapaths to which this load balancer -+ applies to. This means that the same load balancer applies to all -+ datapaths in a group. -+ -+ - - - IP to be used as source IP for packets that have been hair-pinned after -diff --git a/tests/automake.mk b/tests/automake.mk -index eea0d00f4..f6f0f0e33 100644 ---- a/tests/automake.mk -+++ b/tests/automake.mk -@@ -310,7 +310,8 @@ CHECK_PYFILES = \ - tests/test-l7.py \ - tests/uuidfilt.py \ - tests/test-tcp-rst.py \ -- tests/check_acl_log.py -+ tests/check_acl_log.py \ -+ tests/scapy-server.py - - EXTRA_DIST += $(CHECK_PYFILES) - PYCOV_CLEAN_FILES += $(CHECK_PYFILES:.py=.py,cover) .coverage -diff --git a/tests/checkpatch.at b/tests/checkpatch.at -index 26f319705..e7322fff4 100755 ---- a/tests/checkpatch.at -+++ b/tests/checkpatch.at -@@ -8,7 +8,14 @@ OVS_START_SHELL_HELPERS - try_checkpatch() { - # Take the patch to test from $1. Remove an initial four-space indent - # from it and, if it is just headers with no body, add a null body. -+ # If it does not have a 'Subject', add a valid one. - echo "$1" | sed 's/^ //' > test.patch -+ if grep 'Subject\:' test.patch >/dev/null 2>&1; then : -+ else -+ sed -i'' -e '1i\ -+Subject: Patch this is. -+' test.patch -+ fi - if grep '---' expout >/dev/null 2>&1; then : - else - printf '\n---\n' >> test.patch -@@ -236,6 +243,22 @@ done - AT_CLEANUP - - -+AT_SETUP([checkpatch - catastrophic backtracking]) -+dnl Special case this rather than using the above construct because sometimes a -+dnl warning needs to be generated for line lengths (f.e. when the 'while' -+dnl keyword is used). -+try_checkpatch \ -+ "COMMON_PATCH_HEADER -+ + if (!b_ctx_in->chassis_rec || !b_ctx_in->br_int || !b_ctx_in->ovs_idl_txn) -+ " \ -+ "ERROR: Inappropriate bracing around statement -+ #8 FILE: A.c:1: -+ if (!b_ctx_in->chassis_rec || !b_ctx_in->br_int || !b_ctx_in->ovs_idl_txn) -+" -+ -+AT_CLEANUP -+ -+ - AT_SETUP([checkpatch - parenthesized constructs - for]) - try_checkpatch \ - "COMMON_PATCH_HEADER -@@ -560,3 +583,25 @@ try_checkpatch \ - " - - AT_CLEANUP -+ -+AT_SETUP([checkpatch - subject]) -+try_checkpatch \ -+ "Author: A -+ Commit: A -+ Subject: netdev: invalid case and dot ending -+ -+ Signed-off-by: A" \ -+ "WARNING: The subject summary should start with a capital. -+ WARNING: The subject summary should end with a dot. -+ Subject: netdev: invalid case and dot ending" -+ -+try_checkpatch \ -+ "Author: A -+ Commit: A -+ Subject: netdev: This is a way to long commit summary and therefor it should report a WARNING! -+ -+ Signed-off-by: A" \ -+ "WARNING: The subject, ':

      ', is over 70 characters, i.e., 85. -+ Subject: netdev: This is a way to long commit summary and therefor it should report a WARNING!" -+ -+AT_CLEANUP -diff --git a/tests/multinode.at b/tests/multinode.at -index 2b199b4bc..0187382be 100644 ---- a/tests/multinode.at -+++ b/tests/multinode.at -@@ -42,7 +42,6 @@ M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.4 | F - 3 packets transmitted, 3 received, 0% packet loss, time 0ms - ]) - -- - # Create the second logical switch with one port - check multinode_nbctl ls-add sw1 - check multinode_nbctl lsp-add sw1 sw1-port1 -@@ -72,3 +71,815 @@ M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 20.0.0.3 | F - ]) - - AT_CLEANUP -+ -+AT_SETUP([ovn multinode pmtu - distributed router - geneve]) -+ -+# Check that ovn-fake-multinode setup is up and running -+check_fake_multinode_setup -+ -+# Delete the multinode NB and OVS resources before starting the test. -+cleanup_multinode_resources -+ -+m_as ovn-chassis-1 ip link del sw0p1-p -+m_as ovn-chassis-2 ip link del sw0p2-p -+m_as ovn-chassis-2 ip link del sw1p1-p -+ -+# Reset geneve tunnels -+for c in ovn-chassis-1 ovn-chassis-2 ovn-gw-1 -+do -+ m_as $c ovs-vsctl set open . external-ids:ovn-encap-type=geneve -+done -+ -+OVS_WAIT_UNTIL([m_as ovn-chassis-1 ip link show | grep -q genev_sys]) -+OVS_WAIT_UNTIL([m_as ovn-chassis-2 ip link show | grep -q genev_sys]) -+OVS_WAIT_UNTIL([m_as ovn-gw-1 ip link show | grep -q genev_sys]) -+ -+# Test East-West switching -+check multinode_nbctl ls-add sw0 -+check multinode_nbctl lsp-add sw0 sw0-port1 -+check multinode_nbctl lsp-set-addresses sw0-port1 "50:54:00:00:00:03 10.0.0.3 1000::3" -+check multinode_nbctl lsp-add sw0 sw0-port2 -+check multinode_nbctl lsp-set-addresses sw0-port2 "50:54:00:00:00:04 10.0.0.4 1000::4" -+ -+m_as ovn-chassis-1 /data/create_fake_vm.sh sw0-port1 sw0p1 50:54:00:00:00:03 10.0.0.3 24 10.0.0.1 1000::3/64 1000::a -+m_as ovn-chassis-2 /data/create_fake_vm.sh sw0-port2 sw0p2 50:54:00:00:00:04 10.0.0.4 24 10.0.0.1 1000::4/64 1000::a -+ -+m_wait_for_ports_up -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.4 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+# Create the second logical switch with one port -+check multinode_nbctl ls-add sw1 -+check multinode_nbctl lsp-add sw1 sw1-port1 -+check multinode_nbctl lsp-set-addresses sw1-port1 "40:54:00:00:00:03 20.0.0.3 2000::3" -+ -+# Create a logical router and attach both logical switches -+check multinode_nbctl lr-add lr0 -+check multinode_nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 1000::a/64 -+check multinode_nbctl lsp-add sw0 sw0-lr0 -+check multinode_nbctl lsp-set-type sw0-lr0 router -+check multinode_nbctl lsp-set-addresses sw0-lr0 router -+check multinode_nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0 -+ -+check multinode_nbctl lrp-add lr0 lr0-sw1 00:00:00:00:ff:02 20.0.0.1/24 2000::a/64 -+check multinode_nbctl lsp-add sw1 sw1-lr0 -+check multinode_nbctl lsp-set-type sw1-lr0 router -+check multinode_nbctl lsp-set-addresses sw1-lr0 router -+check multinode_nbctl lsp-set-options sw1-lr0 router-port=lr0-sw1 -+ -+m_as ovn-chassis-2 /data/create_fake_vm.sh sw1-port1 sw1p1 40:54:00:00:00:03 20.0.0.3 24 20.0.0.1 2000::3/64 2000::a -+ -+# create exteranl connection for N/S traffic -+check multinode_nbctl ls-add public -+check multinode_nbctl lsp-add public ln-lublic -+check multinode_nbctl lsp-set-type ln-lublic localnet -+check multinode_nbctl lsp-set-addresses ln-lublic unknown -+check multinode_nbctl lsp-set-options ln-lublic network_name=public -+ -+check multinode_nbctl lrp-add lr0 lr0-public 00:11:22:00:ff:01 172.20.0.100/24 -+check multinode_nbctl lsp-add public public-lr0 -+check multinode_nbctl lsp-set-type public-lr0 router -+check multinode_nbctl lsp-set-addresses public-lr0 router -+check multinode_nbctl lsp-set-options public-lr0 router-port=lr0-public -+check multinode_nbctl lrp-set-gateway-chassis lr0-public ovn-gw-1 10 -+check multinode_nbctl lr-route-add lr0 0.0.0.0/0 172.20.0.1 -+ -+check multinode_nbctl lr-nat-add lr0 snat 172.20.0.100 10.0.0.0/24 -+check multinode_nbctl lr-nat-add lr0 snat 172.20.0.100 20.0.0.0/24 -+ -+# create some ACLs -+check multinode_nbctl acl-add sw0 from-lport 1002 'ip4 || ip6' allow-related -+check multinode_nbctl acl-add sw1 from-lport 1002 'ip4 || ip6' allow-related -+ -+m_as ovn-gw-1 ip netns add ovn-ext0 -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext0 -- set interface ext0 type=internal -+m_as ovn-gw-1 ip link set ext0 netns ovn-ext0 -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip link set ext0 up -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip addr add 172.20.0.1/24 dev ext0 -+ -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext1 -- set interface ext1 type=internal -+m_as ovn-gw-1 ip link set ext1 netns ovn-ext0 -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip link set ext1 up -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip addr add 172.20.1.1/24 dev ext1 -+ -+m_as ovn-gw-1 ip netns add ovn-ext2 -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext2 -- set interface ext2 type=internal -+m_as ovn-gw-1 ip link set ext2 netns ovn-ext2 -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip link set ext2 up -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip addr add 172.20.1.2/24 dev ext2 -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip route add default via 172.20.1.1 dev ext2 -+ -+m_as ovn-gw-1 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+m_as ovn-chassis-1 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+m_as ovn-chassis-2 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+ -+m_wait_for_ports_up sw1-port1 -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 20.0.0.3 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+# Change ptmu for the geneve tunnel -+m_as ovn-chassis-1 ip route change 170.168.0.0/16 mtu 1200 dev eth1 -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -c 5 -s 1300 -M do 20.0.0.3 2>&1 |grep -q "message too long, mtu=1142"]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route flush dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add 10.0.0.0/24 dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add default via 10.0.0.1 dev sw0p1]) -+ -+m_as ovn-chassis-1 ip route change 170.168.0.0/16 mtu 1400 dev eth1 -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping6 -c 5 -s 1450 -M do 2000::3 2>&1 |grep -q "message too long, mtu: 1342"]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 172.20.1.2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+M_NS_CHECK_EXEC([ovn-gw-1], [ovn-ext0], [ip link set dev ext1 mtu 1000]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -c 10 -s 1300 -M do 172.20.1.2 2>&1 |grep -q "mtu = 1000"]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 172.20.1.2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+AT_CLEANUP -+ -+AT_SETUP([ovn multinode pmtu - distributed router - vxlan]) -+ -+# Check that ovn-fake-multinode setup is up and running -+check_fake_multinode_setup -+ -+# Delete the multinode NB and OVS resources before starting the test. -+cleanup_multinode_resources -+ -+m_as ovn-chassis-1 ip link del sw0p1-p -+m_as ovn-chassis-2 ip link del sw0p2-p -+m_as ovn-chassis-2 ip link del sw1p1-p -+ -+# Reset vxlan tunnels -+for c in ovn-chassis-1 ovn-chassis-2 ovn-gw-1 -+do -+ m_as $c ovs-vsctl set open . external-ids:ovn-encap-type=vxlan -+done -+ -+OVS_WAIT_UNTIL([m_as ovn-chassis-1 ip link show | grep -q vxlan_sys]) -+OVS_WAIT_UNTIL([m_as ovn-chassis-2 ip link show | grep -q vxlan_sys]) -+OVS_WAIT_UNTIL([m_as ovn-gw-1 ip link show | grep -q vxlan_sys]) -+ -+# Test East-West switching -+check multinode_nbctl ls-add sw0 -+check multinode_nbctl lsp-add sw0 sw0-port1 -+check multinode_nbctl lsp-set-addresses sw0-port1 "50:54:00:00:00:03 10.0.0.3 1000::3" -+check multinode_nbctl lsp-add sw0 sw0-port2 -+check multinode_nbctl lsp-set-addresses sw0-port2 "50:54:00:00:00:04 10.0.0.4 1000::4" -+ -+m_as ovn-chassis-1 /data/create_fake_vm.sh sw0-port1 sw0p1 50:54:00:00:00:03 10.0.0.3 24 10.0.0.1 1000::3/64 1000::a -+m_as ovn-chassis-2 /data/create_fake_vm.sh sw0-port2 sw0p2 50:54:00:00:00:04 10.0.0.4 24 10.0.0.1 1000::4/64 1000::a -+ -+m_wait_for_ports_up -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.4 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+# Create the second logical switch with one port -+check multinode_nbctl ls-add sw1 -+check multinode_nbctl lsp-add sw1 sw1-port1 -+check multinode_nbctl lsp-set-addresses sw1-port1 "40:54:00:00:00:03 20.0.0.3 2000::3" -+ -+# Create a logical router and attach both logical switches -+check multinode_nbctl lr-add lr0 -+check multinode_nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 1000::a/64 -+check multinode_nbctl lsp-add sw0 sw0-lr0 -+check multinode_nbctl lsp-set-type sw0-lr0 router -+check multinode_nbctl lsp-set-addresses sw0-lr0 router -+check multinode_nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0 -+ -+check multinode_nbctl lrp-add lr0 lr0-sw1 00:00:00:00:ff:02 20.0.0.1/24 2000::a/64 -+check multinode_nbctl lsp-add sw1 sw1-lr0 -+check multinode_nbctl lsp-set-type sw1-lr0 router -+check multinode_nbctl lsp-set-addresses sw1-lr0 router -+check multinode_nbctl lsp-set-options sw1-lr0 router-port=lr0-sw1 -+ -+m_as ovn-chassis-2 /data/create_fake_vm.sh sw1-port1 sw1p1 40:54:00:00:00:03 20.0.0.3 24 20.0.0.1 2000::3/64 2000::a -+ -+# create exteranl connection for N/S traffic -+check multinode_nbctl ls-add public -+check multinode_nbctl lsp-add public ln-lublic -+check multinode_nbctl lsp-set-type ln-lublic localnet -+check multinode_nbctl lsp-set-addresses ln-lublic unknown -+check multinode_nbctl lsp-set-options ln-lublic network_name=public -+ -+check multinode_nbctl lrp-add lr0 lr0-public 00:11:22:00:ff:01 172.20.0.100/24 -+check multinode_nbctl lsp-add public public-lr0 -+check multinode_nbctl lsp-set-type public-lr0 router -+check multinode_nbctl lsp-set-addresses public-lr0 router -+check multinode_nbctl lsp-set-options public-lr0 router-port=lr0-public -+check multinode_nbctl lrp-set-gateway-chassis lr0-public ovn-gw-1 10 -+check multinode_nbctl lr-route-add lr0 0.0.0.0/0 172.20.0.1 -+ -+check multinode_nbctl lr-nat-add lr0 snat 172.20.0.100 10.0.0.0/24 -+check multinode_nbctl lr-nat-add lr0 snat 172.20.0.100 20.0.0.0/24 -+ -+# create some ACLs -+check multinode_nbctl acl-add sw0 from-lport 1002 'ip4 || ip6' allow-related -+check multinode_nbctl acl-add sw1 from-lport 1002 'ip4 || ip6' allow-related -+ -+m_as ovn-gw-1 ip netns add ovn-ext0 -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext0 -- set interface ext0 type=internal -+m_as ovn-gw-1 ip link set ext0 netns ovn-ext0 -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip link set ext0 up -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip addr add 172.20.0.1/24 dev ext0 -+ -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext1 -- set interface ext1 type=internal -+m_as ovn-gw-1 ip link set ext1 netns ovn-ext0 -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip link set ext1 up -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip addr add 172.20.1.1/24 dev ext1 -+ -+m_as ovn-gw-1 ip netns add ovn-ext2 -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext2 -- set interface ext2 type=internal -+m_as ovn-gw-1 ip link set ext2 netns ovn-ext2 -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip link set ext2 up -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip addr add 172.20.1.2/24 dev ext2 -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip route add default via 172.20.1.1 dev ext2 -+ -+m_as ovn-gw-1 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+m_as ovn-chassis-1 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+m_as ovn-chassis-2 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+ -+m_wait_for_ports_up sw1-port1 -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 20.0.0.3 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+# Change ptmu for the vxlan tunnel -+m_as ovn-chassis-1 ip route change 170.168.0.0/16 mtu 1200 dev eth1 -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -c 5 -s 1300 -M do 20.0.0.3 2>&1 |grep -q "message too long, mtu=1150"]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route flush dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add 10.0.0.0/24 dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add default via 10.0.0.1 dev sw0p1]) -+ -+M_NS_CHECK_EXEC([ovn-gw-1], [ovn-ext0], [ip link set dev ext1 mtu 1100]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 172.20.1.2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -c 20 -i 0.5 -s 1300 -M do 172.20.1.2 2>&1 |grep -q "mtu = 1150"]) -+ -+AT_CLEANUP -+ -+AT_SETUP([ovn multinode pmtu - gw_router_port - geneve]) -+ -+# Check that ovn-fake-multinode setup is up and running -+check_fake_multinode_setup -+ -+# Delete the multinode NB and OVS resources before starting the test. -+cleanup_multinode_resources -+ -+m_as ovn-chassis-1 ip link del sw0p1-p -+m_as ovn-chassis-2 ip link del sw0p2-p -+m_as ovn-chassis-2 ip link del sw1p1-p -+ -+# Reset geneve tunnels -+for c in ovn-chassis-1 ovn-chassis-2 ovn-gw-1 -+do -+ m_as $c ovs-vsctl set open . external-ids:ovn-encap-type=geneve -+done -+ -+OVS_WAIT_UNTIL([m_as ovn-chassis-1 ip link show | grep -q genev_sys]) -+OVS_WAIT_UNTIL([m_as ovn-chassis-2 ip link show | grep -q genev_sys]) -+OVS_WAIT_UNTIL([m_as ovn-gw-1 ip link show | grep -q genev_sys]) -+ -+# Test East-West switching -+check multinode_nbctl ls-add sw0 -+check multinode_nbctl lsp-add sw0 sw0-port1 -+check multinode_nbctl lsp-set-addresses sw0-port1 "50:54:00:00:00:03 10.0.0.3 1000::3" -+check multinode_nbctl lsp-add sw0 sw0-port2 -+check multinode_nbctl lsp-set-addresses sw0-port2 "50:54:00:00:00:04 10.0.0.4 1000::4" -+ -+m_as ovn-chassis-1 /data/create_fake_vm.sh sw0-port1 sw0p1 50:54:00:00:00:03 10.0.0.3 24 10.0.0.1 1000::3/64 1000::a -+m_as ovn-chassis-2 /data/create_fake_vm.sh sw0-port2 sw0p2 50:54:00:00:00:04 10.0.0.4 24 10.0.0.1 1000::4/64 1000::a -+ -+m_wait_for_ports_up -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.4 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+# Create the second logical switch with one port -+check multinode_nbctl ls-add sw1 -+check multinode_nbctl lsp-add sw1 sw1-port1 -+check multinode_nbctl lsp-set-addresses sw1-port1 "40:54:00:00:00:03 20.0.0.3 2000::3" -+ -+# Create a logical router and attach both logical switches -+check multinode_nbctl lr-add lr0 -+check multinode_nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 1000::a/64 -+check multinode_nbctl lsp-add sw0 sw0-lr0 -+check multinode_nbctl lsp-set-type sw0-lr0 router -+check multinode_nbctl lsp-set-addresses sw0-lr0 router -+check multinode_nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0 -+ -+check multinode_nbctl lrp-add lr0 lr0-sw1 00:00:00:00:ff:02 20.0.0.1/24 2000::a/64 -+check multinode_nbctl lsp-add sw1 sw1-lr0 -+check multinode_nbctl lsp-set-type sw1-lr0 router -+check multinode_nbctl lsp-set-addresses sw1-lr0 router -+check multinode_nbctl lsp-set-options sw1-lr0 router-port=lr0-sw1 -+ -+m_as ovn-chassis-2 /data/create_fake_vm.sh sw1-port1 sw1p1 40:54:00:00:00:03 20.0.0.3 24 20.0.0.1 2000::3/64 2000::a -+ -+# create exteranl connection for N/S traffic -+check multinode_nbctl ls-add public -+check multinode_nbctl lsp-add public ln-lublic -+check multinode_nbctl lsp-set-type ln-lublic localnet -+check multinode_nbctl lsp-set-addresses ln-lublic unknown -+check multinode_nbctl lsp-set-options ln-lublic network_name=public -+ -+check multinode_nbctl lrp-add lr0 lr0-public 00:11:22:00:ff:01 172.20.0.100/24 -+check multinode_nbctl lsp-add public public-lr0 -+check multinode_nbctl lsp-set-type public-lr0 router -+check multinode_nbctl lsp-set-addresses public-lr0 router -+check multinode_nbctl lsp-set-options public-lr0 router-port=lr0-public -+check multinode_nbctl lrp-set-gateway-chassis lr0-public ovn-gw-1 10 -+check multinode_nbctl lr-route-add lr0 0.0.0.0/0 172.20.0.1 -+ -+check multinode_nbctl lr-nat-add lr0 snat 172.20.0.100 10.0.0.0/24 -+check multinode_nbctl lr-nat-add lr0 snat 172.20.0.100 20.0.0.0/24 -+ -+check multinode_nbctl lrp-set-gateway-chassis lr0-sw0 ovn-chassis-1 10 -+check multinode_nbctl lrp-set-gateway-chassis lr0-sw1 ovn-chassis-2 10 -+ -+# create some ACLs -+check multinode_nbctl acl-add sw0 from-lport 1002 'ip4 || ip6' allow-related -+check multinode_nbctl acl-add sw1 from-lport 1002 'ip4 || ip6' allow-related -+ -+m_as ovn-gw-1 ip netns add ovn-ext0 -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext0 -- set interface ext0 type=internal -+m_as ovn-gw-1 ip link set ext0 netns ovn-ext0 -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip link set ext0 up -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip addr add 172.20.0.1/24 dev ext0 -+ -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext1 -- set interface ext1 type=internal -+m_as ovn-gw-1 ip link set ext1 netns ovn-ext0 -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip link set ext1 up -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip addr add 172.20.1.1/24 dev ext1 -+ -+m_as ovn-gw-1 ip netns add ovn-ext2 -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext2 -- set interface ext2 type=internal -+m_as ovn-gw-1 ip link set ext2 netns ovn-ext2 -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip link set ext2 up -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip addr add 172.20.1.2/24 dev ext2 -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip route add default via 172.20.1.1 dev ext2 -+ -+m_as ovn-gw-1 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+m_as ovn-chassis-1 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+m_as ovn-chassis-2 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+ -+m_wait_for_ports_up sw1-port1 -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 20.0.0.3 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route flush dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add 10.0.0.0/24 dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add default via 10.0.0.1 dev sw0p1]) -+ -+m_as ovn-chassis-1 ip route change 170.168.0.0/16 mtu 1200 dev eth1 -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -c 5 -s 1300 -M do 20.0.0.3 2>&1 |grep -q "message too long, mtu=1142"]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route flush dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add 10.0.0.0/24 dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add default via 10.0.0.1 dev sw0p1]) -+ -+m_as ovn-chassis-1 ip route change 170.168.0.0/16 mtu 1400 dev eth1 -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping6 -c 5 -s 1450 -M do 2000::3 2>&1 |grep -q "message too long, mtu: 1342"]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route flush dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add 10.0.0.0/24 dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add default via 10.0.0.1 dev sw0p1]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 172.20.1.2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+M_NS_CHECK_EXEC([ovn-gw-1], [ovn-ext0], [ip link set dev ext1 mtu 1100]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -c 20 -i 0.5 -s 1300 -M do 172.20.1.2 2>&1 |grep -q "mtu = 1100"]) -+ -+AT_CLEANUP -+ -+AT_SETUP([ovn multinode pmtu - gw_router_port - vxlan]) -+ -+# Check that ovn-fake-multinode setup is up and running -+check_fake_multinode_setup -+ -+# Delete the multinode NB and OVS resources before starting the test. -+cleanup_multinode_resources -+ -+m_as ovn-chassis-1 ip link del sw0p1-p -+m_as ovn-chassis-2 ip link del sw0p2-p -+m_as ovn-chassis-2 ip link del sw1p1-p -+ -+# Reset geneve tunnels -+for c in ovn-chassis-1 ovn-chassis-2 ovn-gw-1 -+do -+ m_as $c ovs-vsctl set open . external-ids:ovn-encap-type=vxlan -+done -+ -+OVS_WAIT_UNTIL([m_as ovn-chassis-1 ip link show | grep -q vxlan_sys]) -+OVS_WAIT_UNTIL([m_as ovn-chassis-2 ip link show | grep -q vxlan_sys]) -+OVS_WAIT_UNTIL([m_as ovn-gw-1 ip link show | grep -q vxlan_sys]) -+ -+# Test East-West switching -+check multinode_nbctl ls-add sw0 -+check multinode_nbctl lsp-add sw0 sw0-port1 -+check multinode_nbctl lsp-set-addresses sw0-port1 "50:54:00:00:00:03 10.0.0.3 1000::3" -+check multinode_nbctl lsp-add sw0 sw0-port2 -+check multinode_nbctl lsp-set-addresses sw0-port2 "50:54:00:00:00:04 10.0.0.4 1000::4" -+ -+m_as ovn-chassis-1 /data/create_fake_vm.sh sw0-port1 sw0p1 50:54:00:00:00:03 10.0.0.3 24 10.0.0.1 1000::3/64 1000::a -+m_as ovn-chassis-2 /data/create_fake_vm.sh sw0-port2 sw0p2 50:54:00:00:00:04 10.0.0.4 24 10.0.0.1 1000::4/64 1000::a -+ -+m_wait_for_ports_up -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.4 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+# Create the second logical switch with one port -+check multinode_nbctl ls-add sw1 -+check multinode_nbctl lsp-add sw1 sw1-port1 -+check multinode_nbctl lsp-set-addresses sw1-port1 "40:54:00:00:00:03 20.0.0.3 2000::3" -+ -+# Create a logical router and attach both logical switches -+check multinode_nbctl lr-add lr0 -+check multinode_nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 1000::a/64 -+check multinode_nbctl lsp-add sw0 sw0-lr0 -+check multinode_nbctl lsp-set-type sw0-lr0 router -+check multinode_nbctl lsp-set-addresses sw0-lr0 router -+check multinode_nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0 -+ -+check multinode_nbctl lrp-add lr0 lr0-sw1 00:00:00:00:ff:02 20.0.0.1/24 2000::a/64 -+check multinode_nbctl lsp-add sw1 sw1-lr0 -+check multinode_nbctl lsp-set-type sw1-lr0 router -+check multinode_nbctl lsp-set-addresses sw1-lr0 router -+check multinode_nbctl lsp-set-options sw1-lr0 router-port=lr0-sw1 -+ -+m_as ovn-chassis-2 /data/create_fake_vm.sh sw1-port1 sw1p1 40:54:00:00:00:03 20.0.0.3 24 20.0.0.1 2000::3/64 2000::a -+ -+# create exteranl connection for N/S traffic -+check multinode_nbctl ls-add public -+check multinode_nbctl lsp-add public ln-lublic -+check multinode_nbctl lsp-set-type ln-lublic localnet -+check multinode_nbctl lsp-set-addresses ln-lublic unknown -+check multinode_nbctl lsp-set-options ln-lublic network_name=public -+ -+check multinode_nbctl lrp-add lr0 lr0-public 00:11:22:00:ff:01 172.20.0.100/24 -+check multinode_nbctl lsp-add public public-lr0 -+check multinode_nbctl lsp-set-type public-lr0 router -+check multinode_nbctl lsp-set-addresses public-lr0 router -+check multinode_nbctl lsp-set-options public-lr0 router-port=lr0-public -+check multinode_nbctl lrp-set-gateway-chassis lr0-public ovn-gw-1 10 -+check multinode_nbctl lr-route-add lr0 0.0.0.0/0 172.20.0.1 -+ -+check multinode_nbctl lr-nat-add lr0 snat 172.20.0.100 10.0.0.0/24 -+check multinode_nbctl lr-nat-add lr0 snat 172.20.0.100 20.0.0.0/24 -+ -+check multinode_nbctl lrp-set-gateway-chassis lr0-sw0 ovn-chassis-1 10 -+check multinode_nbctl lrp-set-gateway-chassis lr0-sw1 ovn-chassis-2 10 -+ -+# create some ACLs -+check multinode_nbctl acl-add sw0 from-lport 1002 'ip4 || ip6' allow-related -+check multinode_nbctl acl-add sw1 from-lport 1002 'ip4 || ip6' allow-related -+ -+m_as ovn-gw-1 ip netns add ovn-ext0 -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext0 -- set interface ext0 type=internal -+m_as ovn-gw-1 ip link set ext0 netns ovn-ext0 -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip link set ext0 up -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip addr add 172.20.0.1/24 dev ext0 -+ -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext1 -- set interface ext1 type=internal -+m_as ovn-gw-1 ip link set ext1 netns ovn-ext0 -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip link set ext1 up -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip addr add 172.20.1.1/24 dev ext1 -+ -+m_as ovn-gw-1 ip netns add ovn-ext2 -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext2 -- set interface ext2 type=internal -+m_as ovn-gw-1 ip link set ext2 netns ovn-ext2 -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip link set ext2 up -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip addr add 172.20.1.2/24 dev ext2 -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip route add default via 172.20.1.1 dev ext2 -+ -+m_as ovn-gw-1 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+m_as ovn-chassis-1 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+m_as ovn-chassis-2 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+ -+m_wait_for_ports_up sw1-port1 -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 20.0.0.3 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route flush dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add 10.0.0.0/24 dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add default via 10.0.0.1 dev sw0p1]) -+ -+m_as ovn-chassis-1 ip route change 170.168.0.0/16 mtu 1200 dev eth1 -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -c 5 -s 1300 -M do 20.0.0.3 2>&1 |grep -q "message too long, mtu=1150"]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route flush dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add 10.0.0.0/24 dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add default via 10.0.0.1 dev sw0p1]) -+ -+M_NS_CHECK_EXEC([ovn-gw-1], [ovn-ext0], [ip link set dev ext1 mtu 1100]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 172.20.1.2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -c 20 -i 0.5 -s 1300 -M do 172.20.1.2 2>&1 |grep -q "mtu = 1150"]) -+ -+AT_CLEANUP -+ -+AT_SETUP([ovn multinode pmtu - gw router - geneve]) -+ -+# Check that ovn-fake-multinode setup is up and running -+check_fake_multinode_setup -+ -+# Delete the multinode NB and OVS resources before starting the test. -+cleanup_multinode_resources -+ -+m_as ovn-chassis-1 ip link del sw0p1-p -+m_as ovn-chassis-2 ip link del sw0p2-p -+m_as ovn-chassis-2 ip link del sw1p1-p -+ -+# Reset geneve tunnels -+for c in ovn-chassis-1 ovn-chassis-2 ovn-gw-1 -+do -+ m_as $c ovs-vsctl set open . external-ids:ovn-encap-type=geneve -+done -+ -+OVS_WAIT_UNTIL([m_as ovn-chassis-1 ip link show | grep -q genev_sys]) -+OVS_WAIT_UNTIL([m_as ovn-chassis-2 ip link show | grep -q genev_sys]) -+OVS_WAIT_UNTIL([m_as ovn-gw-1 ip link show | grep -q genev_sys]) -+ -+# Test East-West switching -+check multinode_nbctl ls-add sw0 -+check multinode_nbctl lsp-add sw0 sw0-port1 -+check multinode_nbctl lsp-set-addresses sw0-port1 "50:54:00:00:00:03 10.0.0.3 1000::3" -+check multinode_nbctl lsp-add sw0 sw0-port2 -+check multinode_nbctl lsp-set-addresses sw0-port2 "50:54:00:00:00:04 10.0.0.4 1000::4" -+ -+m_as ovn-chassis-1 /data/create_fake_vm.sh sw0-port1 sw0p1 50:54:00:00:00:03 10.0.0.3 24 10.0.0.1 1000::3/64 1000::a -+m_as ovn-chassis-2 /data/create_fake_vm.sh sw0-port2 sw0p2 50:54:00:00:00:04 10.0.0.4 24 10.0.0.1 1000::4/64 1000::a -+ -+m_wait_for_ports_up -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.4 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+# Create the second logical switch with one port -+check multinode_nbctl ls-add sw1 -+check multinode_nbctl lsp-add sw1 sw1-port1 -+check multinode_nbctl lsp-set-addresses sw1-port1 "40:54:00:00:00:03 20.0.0.3 2000::3" -+ -+# Create a logical router and attach both logical switches -+check multinode_nbctl lr-add lr0 -- set Logical_Router lr0 options:chassis=ovn-gw-1 -+check multinode_nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 1000::a/64 -+check multinode_nbctl lsp-add sw0 sw0-lr0 -+check multinode_nbctl lsp-set-type sw0-lr0 router -+check multinode_nbctl lsp-set-addresses sw0-lr0 router -+check multinode_nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0 -+ -+check multinode_nbctl lrp-add lr0 lr0-sw1 00:00:00:00:ff:02 20.0.0.1/24 2000::a/64 -+check multinode_nbctl lsp-add sw1 sw1-lr0 -+check multinode_nbctl lsp-set-type sw1-lr0 router -+check multinode_nbctl lsp-set-addresses sw1-lr0 router -+check multinode_nbctl lsp-set-options sw1-lr0 router-port=lr0-sw1 -+ -+m_as ovn-chassis-2 /data/create_fake_vm.sh sw1-port1 sw1p1 40:54:00:00:00:03 20.0.0.3 24 20.0.0.1 2000::3/64 2000::a -+ -+# create exteranl connection for N/S traffic -+check multinode_nbctl ls-add public -+check multinode_nbctl lsp-add public ln-lublic -+check multinode_nbctl lsp-set-type ln-lublic localnet -+check multinode_nbctl lsp-set-addresses ln-lublic unknown -+check multinode_nbctl lsp-set-options ln-lublic network_name=public -+ -+check multinode_nbctl lrp-add lr0 lr0-public 00:11:22:00:ff:01 172.20.0.100/24 -+check multinode_nbctl lsp-add public public-lr0 -+check multinode_nbctl lsp-set-type public-lr0 router -+check multinode_nbctl lsp-set-addresses public-lr0 router -+check multinode_nbctl lsp-set-options public-lr0 router-port=lr0-public -+check multinode_nbctl lr-route-add lr0 0.0.0.0/0 172.20.0.1 -+ -+check multinode_nbctl lr-nat-add lr0 snat 172.20.0.100 10.0.0.0/24 -+check multinode_nbctl lr-nat-add lr0 snat 172.20.0.100 20.0.0.0/24 -+ -+# create some ACLs -+check multinode_nbctl acl-add sw0 from-lport 1002 'ip4 || ip6' allow-related -+check multinode_nbctl acl-add sw1 from-lport 1002 'ip4 || ip6' allow-related -+ -+m_as ovn-gw-1 ip netns add ovn-ext0 -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext0 -- set interface ext0 type=internal -+m_as ovn-gw-1 ip link set ext0 netns ovn-ext0 -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip link set ext0 up -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip addr add 172.20.0.1/24 dev ext0 -+ -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext1 -- set interface ext1 type=internal -+m_as ovn-gw-1 ip link set ext1 netns ovn-ext0 -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip link set ext1 up -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip addr add 172.20.1.1/24 dev ext1 -+ -+m_as ovn-gw-1 ip netns add ovn-ext2 -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext2 -- set interface ext2 type=internal -+m_as ovn-gw-1 ip link set ext2 netns ovn-ext2 -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip link set ext2 up -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip addr add 172.20.1.2/24 dev ext2 -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip route add default via 172.20.1.1 dev ext2 -+ -+m_as ovn-gw-1 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+m_as ovn-chassis-1 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+m_as ovn-chassis-2 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+ -+m_wait_for_ports_up sw1-port1 -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 20.0.0.3 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route flush dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add 10.0.0.0/24 dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add default via 10.0.0.1 dev sw0p1]) -+ -+m_as ovn-chassis-1 ip route change 170.168.0.0/16 mtu 1200 dev eth1 -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -c 5 -s 1300 -M do 20.0.0.3 2>&1 |grep -q "message too long, mtu=1142"]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route flush dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add 10.0.0.0/24 dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add default via 10.0.0.1 dev sw0p1]) -+ -+m_as ovn-chassis-1 ip route change 170.168.0.0/16 mtu 1400 dev eth1 -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping6 -c 5 -s 1450 -M do 2000::3 2>&1 |grep -q "message too long, mtu: 1342"]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route flush dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add 10.0.0.0/24 dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add default via 10.0.0.1 dev sw0p1]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 172.20.1.2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+M_NS_CHECK_EXEC([ovn-gw-1], [ovn-ext0], [ip link set dev ext1 mtu 1100]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -c 20 -i 0.5 -s 1300 -M do 172.20.1.2 2>&1 |grep -q "mtu = 1100"]) -+ -+AT_CLEANUP -+ -+AT_SETUP([ovn multinode pmtu - gw router - vxlan]) -+ -+# Check that ovn-fake-multinode setup is up and running -+check_fake_multinode_setup -+ -+# Delete the multinode NB and OVS resources before starting the test. -+cleanup_multinode_resources -+ -+m_as ovn-chassis-1 ip link del sw0p1-p -+m_as ovn-chassis-2 ip link del sw0p2-p -+m_as ovn-chassis-2 ip link del sw1p1-p -+ -+# Reset geneve tunnels -+for c in ovn-chassis-1 ovn-chassis-2 ovn-gw-1 -+do -+ m_as $c ovs-vsctl set open . external-ids:ovn-encap-type=vxlan -+done -+ -+OVS_WAIT_UNTIL([m_as ovn-chassis-1 ip link show | grep -q vxlan_sys]) -+OVS_WAIT_UNTIL([m_as ovn-chassis-2 ip link show | grep -q vxlan_sys]) -+OVS_WAIT_UNTIL([m_as ovn-gw-1 ip link show | grep -q vxlan_sys]) -+ -+# Test East-West switching -+check multinode_nbctl ls-add sw0 -+check multinode_nbctl lsp-add sw0 sw0-port1 -+check multinode_nbctl lsp-set-addresses sw0-port1 "50:54:00:00:00:03 10.0.0.3 1000::3" -+check multinode_nbctl lsp-add sw0 sw0-port2 -+check multinode_nbctl lsp-set-addresses sw0-port2 "50:54:00:00:00:04 10.0.0.4 1000::4" -+ -+m_as ovn-chassis-1 /data/create_fake_vm.sh sw0-port1 sw0p1 50:54:00:00:00:03 10.0.0.3 24 10.0.0.1 1000::3/64 1000::a -+m_as ovn-chassis-2 /data/create_fake_vm.sh sw0-port2 sw0p2 50:54:00:00:00:04 10.0.0.4 24 10.0.0.1 1000::4/64 1000::a -+ -+m_wait_for_ports_up -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.4 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+# Create the second logical switch with one port -+check multinode_nbctl ls-add sw1 -+check multinode_nbctl lsp-add sw1 sw1-port1 -+check multinode_nbctl lsp-set-addresses sw1-port1 "40:54:00:00:00:03 20.0.0.3 2000::3" -+ -+# Create a logical router and attach both logical switches -+check multinode_nbctl lr-add lr0 -- set Logical_Router lr0 options:chassis=ovn-gw-1 -+check multinode_nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 1000::a/64 -+check multinode_nbctl lsp-add sw0 sw0-lr0 -+check multinode_nbctl lsp-set-type sw0-lr0 router -+check multinode_nbctl lsp-set-addresses sw0-lr0 router -+check multinode_nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0 -+ -+check multinode_nbctl lrp-add lr0 lr0-sw1 00:00:00:00:ff:02 20.0.0.1/24 2000::a/64 -+check multinode_nbctl lsp-add sw1 sw1-lr0 -+check multinode_nbctl lsp-set-type sw1-lr0 router -+check multinode_nbctl lsp-set-addresses sw1-lr0 router -+check multinode_nbctl lsp-set-options sw1-lr0 router-port=lr0-sw1 -+ -+m_as ovn-chassis-2 /data/create_fake_vm.sh sw1-port1 sw1p1 40:54:00:00:00:03 20.0.0.3 24 20.0.0.1 2000::3/64 2000::a -+ -+# create exteranl connection for N/S traffic -+check multinode_nbctl ls-add public -+check multinode_nbctl lsp-add public ln-lublic -+check multinode_nbctl lsp-set-type ln-lublic localnet -+check multinode_nbctl lsp-set-addresses ln-lublic unknown -+check multinode_nbctl lsp-set-options ln-lublic network_name=public -+ -+check multinode_nbctl lrp-add lr0 lr0-public 00:11:22:00:ff:01 172.20.0.100/24 -+check multinode_nbctl lsp-add public public-lr0 -+check multinode_nbctl lsp-set-type public-lr0 router -+check multinode_nbctl lsp-set-addresses public-lr0 router -+check multinode_nbctl lsp-set-options public-lr0 router-port=lr0-public -+check multinode_nbctl lr-route-add lr0 0.0.0.0/0 172.20.0.1 -+ -+check multinode_nbctl lr-nat-add lr0 snat 172.20.0.100 10.0.0.0/24 -+check multinode_nbctl lr-nat-add lr0 snat 172.20.0.100 20.0.0.0/24 -+ -+# create some ACLs -+check multinode_nbctl acl-add sw0 from-lport 1002 'ip4 || ip6' allow-related -+check multinode_nbctl acl-add sw1 from-lport 1002 'ip4 || ip6' allow-related -+ -+m_as ovn-gw-1 ip netns add ovn-ext0 -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext0 -- set interface ext0 type=internal -+m_as ovn-gw-1 ip link set ext0 netns ovn-ext0 -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip link set ext0 up -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip addr add 172.20.0.1/24 dev ext0 -+ -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext1 -- set interface ext1 type=internal -+m_as ovn-gw-1 ip link set ext1 netns ovn-ext0 -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip link set ext1 up -+m_as ovn-gw-1 ip netns exec ovn-ext0 ip addr add 172.20.1.1/24 dev ext1 -+ -+m_as ovn-gw-1 ip netns add ovn-ext2 -+m_as ovn-gw-1 ovs-vsctl add-port br-ex ext2 -- set interface ext2 type=internal -+m_as ovn-gw-1 ip link set ext2 netns ovn-ext2 -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip link set ext2 up -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip addr add 172.20.1.2/24 dev ext2 -+m_as ovn-gw-1 ip netns exec ovn-ext2 ip route add default via 172.20.1.1 dev ext2 -+ -+m_as ovn-gw-1 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+m_as ovn-chassis-1 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+m_as ovn-chassis-2 ovs-vsctl set open . external-ids:ovn-bridge-mappings=public:br-ex -+ -+m_wait_for_ports_up sw1-port1 -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 20.0.0.3 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route flush dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add 10.0.0.0/24 dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add default via 10.0.0.1 dev sw0p1]) -+ -+m_as ovn-chassis-1 ip route change 170.168.0.0/16 mtu 1200 dev eth1 -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -c 5 -s 1300 -M do 20.0.0.3 2>&1 |grep -q "message too long, mtu=1150"]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route flush dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add 10.0.0.0/24 dev sw0p1]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ip route add default via 10.0.0.1 dev sw0p1]) -+ -+M_NS_CHECK_EXEC([ovn-gw-1], [ovn-ext0], [ip link set dev ext1 mtu 1100]) -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -q -c 3 -i 0.3 -w 2 172.20.1.2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) -+ -+M_NS_CHECK_EXEC([ovn-chassis-1], [sw0p1], [ping -c 20 -i 0.5 -s 1300 -M do 172.20.1.2 2>&1 |grep -q "mtu = 1150"]) -+ -+AT_CLEANUP -diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at -index 07ef1d092..bccedbaf7 100644 ---- a/tests/ofproto-macros.at -+++ b/tests/ofproto-macros.at -@@ -200,14 +200,14 @@ m4_define([_OVS_VSWITCHD_START], - AT_CHECK([[sed < stderr ' - /vlog|INFO|opened log file/d - /ovsdb_server|INFO|ovsdb-server (Open vSwitch)/d']]) -- AT_CAPTURE_FILE([ovsdb-server.log]) -+ # AT_CAPTURE_FILE([ovsdb-server.log]) - - dnl Initialize database. - AT_CHECK([ovs-vsctl --no-wait init $2]) - - dnl Start ovs-vswitchd. - AT_CHECK([ovs-vswitchd $1 --detach --no-chdir --pidfile --log-file -vvconn -vofproto_dpif -vunixctl], [0], [], [stderr]) -- AT_CAPTURE_FILE([ovs-vswitchd.log]) -+ #AT_CAPTURE_FILE([ovs-vswitchd.log]) - on_exit "kill_ovs_vswitchd `cat ovs-vswitchd.pid`" - AT_CHECK([[sed < stderr ' - /ovs_numa|INFO|Discovered /d -diff --git a/tests/ovn-controller-vtep.at b/tests/ovn-controller-vtep.at -index 73971b3f4..7f7d1cf40 100644 ---- a/tests/ovn-controller-vtep.at -+++ b/tests/ovn-controller-vtep.at -@@ -50,7 +50,7 @@ m4_define([OVN_CONTROLLER_VTEP_START], [ - /vlog|INFO|opened log file/d' - - dnl Wait until ovs-vtep starts up. -- OVS_WAIT_UNTIL([test -n "`vtep-ctl show | grep Physical_Port`"]) -+ OVS_WAIT_UNTIL([test 2 -eq "`vtep-ctl show | grep -c Physical_Port`"]) - - dnl Start ovn-controller-vtep. - start_daemon ovn-controller-vtep --vtep-db=unix:"$ovs_dir"/db.sock \ -@@ -653,9 +653,6 @@ AT_CHECK([grep -c $northd_version vtep1/ovn-controller-vtep.log], [0], [1 - as northd - OVS_APP_EXIT_AND_WAIT([ovn-northd]) - --as northd-backup --OVS_APP_EXIT_AND_WAIT([ovn-northd]) -- - check ovn-sbctl set SB_Global . options:northd_internal_version=foo - check ovn-sbctl set Chassis vtep1 vtep_logical_switches=foo - -diff --git a/tests/ovn-controller.at b/tests/ovn-controller.at -index 4212d601a..b2a38a969 100644 ---- a/tests/ovn-controller.at -+++ b/tests/ovn-controller.at -@@ -60,7 +60,6 @@ check_bridge_mappings () { - # the RBAC rules programmed into the SB-DB. The test instruments the SB-DB - # directly and we need to stop northd to avoid overwriting the instrumentation. - kill `cat northd/ovn-northd.pid` --kill `cat northd-backup/ovn-northd.pid` - kill `cat ovn-nb/ovsdb-server.pid` - - # Initially there should be no patch ports. -@@ -214,6 +213,13 @@ if test X$HAVE_OPENSSL = Xyes; then - # TODO implement check for change of certificates in ovn-controller - # and remove this workaround. - ovs-vsctl set Open_vSwitch . external-ids:ovn-remote=unix:/dev/null -+ # Make sure that the ovn-remote change is handled by ovn-controller. -+ # Without this, ovn-controller could handle both this change and next ovn-remote change within the same loop, -+ # resulting in no change. -+ # Use 2 ovn-appctl to guarentee that ovn-controller run the full loop, and not just the unixctl handling -+ OVS_WAIT_UNTIL([test x$(ovn-appctl -t ovn-controller debug/status) = "xrunning"]) -+ OVS_WAIT_UNTIL([test x$(ovn-appctl -t ovn-controller debug/status) = "xrunning"]) -+ - fi - ovs-vsctl -- set Open_vSwitch . external-ids:hostname="${sysid}" \ - -- set Open_vSwitch . external-ids:system-id="${sysid}" \ -@@ -526,6 +532,10 @@ OVS_WAIT_UNTIL([ - test "$(ovn-sbctl get chassis hv1 other_config:port-up-notif)" = '"true"' - ]) - -+OVS_WAIT_UNTIL([ -+ test "$(ovn-sbctl get chassis hv1 other_config:ls-dpg-column)" = '"true"' -+]) -+ - OVN_CLEANUP([hv1]) - AT_CLEANUP - ]) -@@ -575,10 +585,8 @@ localport lport : [[lsp1]] - - # pause ovn-northd - check as northd ovn-appctl -t ovn-northd pause --check as northd-backup ovn-appctl -t ovn-northd pause - - as northd ovn-appctl -t ovn-northd status --as northd-backup ovn-appctl -t ovn-northd status - - pb_types=(patch chassisredirect l3gateway localnet localport l2gateway - virtual external remote vtep) -@@ -2093,7 +2101,6 @@ AT_CHECK([ovs-ofctl dump-flows br-int table=46 | grep -c "priority=1100"], [0], - - # pause ovn-northd - check as northd ovn-appctl -t ovn-northd pause --check as northd-backup ovn-appctl -t ovn-northd pause - - # Simulate a SB address set "del and add" notification to ovn-controller in the - # same IDL iteration. The flows programmed by ovn-controller should reflect the -@@ -2118,7 +2125,7 @@ AT_CLEANUP - - AT_SETUP([ovn-controller - I-P handle lb_hairpin_use_ct_mark change]) - --ovn_start --backup-northd=none -+ovn_start - - net_add n1 - sim_add hv1 -@@ -2193,14 +2200,18 @@ check ovn-nbctl --wait=hv sync - AT_CHECK([ovn-appctl -t ovn-controller group-table-list | awk '{print $2}' | sort | uniq | wc -l], [0], [2 - ]) - --# Set 5 seconds wait time before clearing OVS flows. --check ovs-vsctl set open . external_ids:ovn-ofctrl-wait-before-clear=5000 -- - # Stop ovn-controller - OVS_APP_EXIT_AND_WAIT([ovn-controller]) - -+# Set 5 seconds wait time before clearing OVS flows. -+check ovs-vsctl set open . external_ids:ovn-ofctrl-wait-before-clear=5000 -+ - # The old OVS flows should remain (this is regardless of the configuration) --AT_CHECK([ovs-ofctl dump-flows br-int | grep 10.1.2.3], [0], [ignore]) -+AT_CHECK([ovs-ofctl dump-flows br-int | grep -F 10.1.2.3], [0], [ignore]) -+ -+# We should have 2 flows with groups. -+AT_CHECK([ovs-ofctl dump-flows br-int | grep group -c], [0], [2 -+]) - - # Make a change to the ls1-lp1's IP - check ovn-nbctl --wait=sb lsp-set-addresses ls1-lp1 "f0:00:00:00:00:01 10.1.2.4" -@@ -2208,16 +2219,29 @@ check ovn-nbctl --wait=sb lsp-set-addresses ls1-lp1 "f0:00:00:00:00:01 10.1.2.4" - # Start ovn-controller, which should compute new flows but not apply them - # until the wait time is completed. - start_daemon ovn-controller --sleep 2 -+ -+# Wait for octrl to run - it will handle the wait-before-clear -+OVS_WAIT_UNTIL([grep -q 'wait-before-clear' hv1/ovn-controller.log]) -+ -+# Check that there is no flow using 10.1.2.4 except the lb one (using 2.2.2.2) -+OVS_WAIT_UNTIL([test 0 = $(ovs-ofctl dump-flows br-int | grep -F 10.1.2.4 | grep -cvF 2.2.2.2)]) - - # Check in the middle of the wait. - lflow_run_1=$(ovn-appctl -t ovn-controller coverage/read-counter lflow_run) --AT_CHECK([ovs-ofctl dump-flows br-int | grep 10.1.2.3], [0], [ignore]) -+AT_CHECK([ovs-ofctl dump-flows br-int | grep -F 10.1.2.3], [0], [ignore]) -+ -+# We should have 2 flows with groups. -+AT_CHECK([ovs-ofctl dump-flows br-int | grep group -c], [0], [2 -+]) - - sleep 5 - - # Check after the wait --OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 10.1.2.4]) -+OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep -F 10.1.2.4 | grep -vF 2.2.2.2]) -+ -+# We should have 2 flows with groups. -+AT_CHECK([ovs-ofctl dump-flows br-int | grep group -c], [0], [2 -+]) - lflow_run_2=$(ovn-appctl -t ovn-controller coverage/read-counter lflow_run) - - # Verify that the flow compute completed during the wait (after the wait it -@@ -2228,9 +2252,9 @@ AT_CHECK_UNQUOTED([echo $lflow_run_1], [0], [$lflow_run_2 - # Restart OVS this time, and wait until flows are reinstalled - OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) - start_daemon ovs-vswitchd --enable-dummy=system -vvconn -vofproto_dpif -vunixctl --OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 10.1.2.4]) -+OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep -F 10.1.2.4 | grep -vF 2.2.2.2]) - --check ovn-nbctl --wait=hv lb-add lb3 2.2.2.2 10.1.2.5 \ -+check ovn-nbctl --wait=hv lb-add lb3 3.3.3.3 10.1.2.5 \ - -- ls-lb-add ls1 lb3 - - # There should be 3 group IDs allocated (this is to ensure the group ID -@@ -2238,6 +2262,10 @@ check ovn-nbctl --wait=hv lb-add lb3 2.2.2.2 10.1.2.5 \ - AT_CHECK([ovn-appctl -t ovn-controller group-table-list | awk '{print $2}' | sort | uniq | wc -l], [0], [3 - ]) - -+# We should have 3 flows with groups. -+AT_CHECK([ovs-ofctl dump-flows br-int | grep group -c], [0], [3 -+]) -+ - OVN_CLEANUP([hv1]) - AT_CLEANUP - -@@ -2651,3 +2679,23 @@ OVS_WAIT_FOR_OUTPUT([as hv1 ovs-ofctl dump-flows br-int table=0 | grep -c in_por - OVN_CLEANUP([hv1]) - AT_CLEANUP - ]) -+ -+AT_SETUP([ovn-controller - ssl ciphers using command line options]) -+AT_KEYWORDS([ovn]) -+AT_SKIP_IF([test "$HAVE_OPENSSL" = no]) -+ovn_start -+ -+net_add n1 -+sim_add hv1 -+ovs-vsctl add-br br-phys -+ovn_attach n1 br-phys 192.168.0.20 -+ -+# Set cipher and and it should connect -+OVS_APP_EXIT_AND_WAIT([ovn-controller]) -+start_daemon ovn-controller --ssl-ciphers='HIGH:!aNULL:!MD5:@SECLEVEL=1' --ssl-protocols='TLSv1,TLSv1.1,TLSv1.2' -+ -+OVS_WAIT_FOR_OUTPUT([ovn-appctl -t ovn-controller connection-status], [0], [connected -+]) -+ -+OVN_CLEANUP([hv1]) -+AT_CLEANUP -diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at -index d265bb90b..49e1e39d6 100644 ---- a/tests/ovn-ic.at -+++ b/tests/ovn-ic.at -@@ -28,7 +28,31 @@ availability-zone az3 - ]) - - OVN_CLEANUP_IC([az1], [az2]) -+AT_CLEANUP -+]) -+ -+ -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([ovn-ic -- AZ update in GW]) -+ovn_init_ic_db -+net_add n1 -+ -+ovn_start az1 -+sim_add gw-az1 -+as gw-az1 -+ -+check ovs-vsctl add-br br-phys -+ovn_az_attach az1 n1 br-phys 192.168.1.1 -+check ovs-vsctl set open . external-ids:ovn-is-interconn=true - -+az_uuid=$(fetch_column ic-sb:availability-zone _uuid name="az1") -+ovn_as az1 ovn-nbctl set NB_Global . name="az2" -+wait_column "$az_uuid" ic-sb:availability-zone _uuid name="az2" -+ -+# make sure that gateway still point to the same AZ with new name -+wait_column "$az_uuid" ic-sb:gateway availability_zone name="gw-az1" -+ -+OVN_CLEANUP_IC([az1]) - AT_CLEANUP - ]) - -@@ -92,6 +116,7 @@ check ovn-nbctl lr-add lr1 - check ovn-nbctl lrp-add lr1 lrp1 00:00:00:00:00:01 10.0.0.1/24 - check ovn-nbctl lrp-set-gateway-chassis lrp1 gw-az1 - -+OVS_WAIT_UNTIL([ovn-nbctl show | grep switch | grep ts1]) - check ovn-nbctl lsp-add ts1 lsp1 -- \ - lsp-set-addresses lsp1 router -- \ - lsp-set-type lsp1 router -- \ -@@ -156,6 +181,7 @@ create_ic_infra() { - ovn_as $az - - check ovn-ic-nbctl ts-add $ts -+ OVS_WAIT_UNTIL([ovn-nbctl show | grep switch | grep $ts]) - check ovn-nbctl lr-add $lr - check ovn-nbctl lrp-add $lr $lrp 00:00:00:00:00:0$az_id 10.0.$az_id.1/24 - check ovn-nbctl lrp-set-gateway-chassis $lrp gw-$az -@@ -227,6 +253,7 @@ for i in 1 2; do - check ovn-nbctl lrp-add lr1 lrp$i 00:00:00:00:0$i:01 10.0.$i.1/24 - check ovn-nbctl lrp-set-gateway-chassis lrp$i gw-az$i - -+ OVS_WAIT_UNTIL([ovn-nbctl show | grep switch | grep ts1]) - check ovn-nbctl lsp-add ts1 lsp$i -- \ - lsp-set-addresses lsp$i router -- \ - lsp-set-type lsp$i router -- \ -@@ -290,7 +317,7 @@ ovs-vsctl set open . external-ids:ovn-is-interconn=true - OVS_WAIT_UNTIL([ovn_as az2 ovn-sbctl show | grep gw1]) - - OVN_CLEANUP_SBOX(gw1) --AT_CHECK([ovn_as az2 ovn-sbctl show], [0], [dnl -+OVS_WAIT_FOR_OUTPUT([ovn_as az2 ovn-sbctl show], [0], [dnl - ]) - - # Test encap change -@@ -335,16 +362,17 @@ ovn-nbctl lsp-add ts1 lsp-ts1-lr1 - ovn-nbctl lsp-set-addresses lsp-ts1-lr1 router - ovn-nbctl lsp-set-type lsp-ts1-lr1 router - ovn-nbctl --wait=hv lsp-set-options lsp-ts1-lr1 router-port=lrp-lr1-ts1 -- -+OVS_WAIT_UNTIL([ovn_as az2 ovn-nbctl show | grep lsp-ts1-lr1]) - ovn_as az2 ovn-nbctl lsp-set-options lsp-ts1-lr1 requested-chassis=gw1 --AT_CHECK([ovn_as az2 ovn-nbctl show | uuidfilt], [0], [dnl -+ -+OVS_WAIT_FOR_OUTPUT([ovn_as az2 ovn-nbctl show | uuidfilt], [0], [dnl - switch <0> (ts1) - port lsp-ts1-lr1 - type: remote - addresses: [["aa:aa:aa:aa:aa:01 169.254.100.1/24"]] - ]) - --AT_CHECK([ovn_as az2 ovn-sbctl -f csv -d bare --no-headings --columns logical_port,type list port_binding], [0], [dnl -+OVS_WAIT_FOR_OUTPUT([ovn_as az2 ovn-sbctl -f csv -d bare --no-headings --columns logical_port,type list port_binding], [0], [dnl - lsp-ts1-lr1,remote - ]) - -@@ -529,6 +557,7 @@ for i in 1 2; do - for j in 1 2; do - ts=ts$j$j - ovn-ic-nbctl --may-exist ts-add $ts -+ OVS_WAIT_UNTIL([ovn-nbctl show | grep switch | grep $ts]) - - # Create LRP and connect to TS - lr=lr$j$i -@@ -552,6 +581,9 @@ ovn_as az1 ovn-nbctl show - echo az2 - ovn_as az2 ovn-nbctl show - -+OVS_WAIT_UNTIL([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep learned | grep 192.168]) -+OVS_WAIT_UNTIL([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep learned | grep 10.10.10]) -+ - # Test routes from lr12 were learned to lr11 - AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr11 | - grep learned | awk '{print $1, $2}' | sort], [0], [dnl -@@ -584,6 +616,7 @@ for i in 1 2; do - # Create LRP and connect to TS - ovn-nbctl lr-add lr$i - ovn-nbctl lrp-add lr$i lrp-lr$i-ts1 aa:aa:aa:aa:aa:0$i 169.254.100.$i/24 -+ OVS_WAIT_UNTIL([ovn-nbctl show | grep switch | grep ts1]) - ovn-nbctl lsp-add ts1 lsp-ts1-lr$i \ - -- lsp-set-addresses lsp-ts1-lr$i router \ - -- lsp-set-type lsp-ts1-lr$i router \ -@@ -909,6 +942,7 @@ for i in 1 2; do - for j in 1 2 3; do - ts=ts1$j - ovn-ic-nbctl --may-exist ts-add $ts -+ OVS_WAIT_UNTIL([ovn-nbctl show | grep switch | grep $ts]) - - lrp=lrp-$lr-$ts - lsp=lsp-$ts-$lr -@@ -934,6 +968,7 @@ for i in 1 2; do - for j in 1 2; do - ts=ts2$j - ovn-ic-nbctl --may-exist ts-add $ts -+ OVS_WAIT_UNTIL([ovn-nbctl show | grep switch | grep $ts]) - - lrp=lrp-$lr-$ts - lsp=lsp-$ts-$lr -@@ -957,7 +992,7 @@ ovn_as az2 ovn-nbctl --route-table=rtb3 lr-route-add lr12 10.10.10.0/24 192.168. - ovn_as az2 ovn-nbctl --wait=sb lrp-add lr22 lrp-lr22 aa:aa:aa:aa:bb:01 "192.168.0.1/24" - - # Test direct routes from lr12 were learned to lr11 --AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 | -+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 | - grep learned | awk '{print $1, $2, $5}' | sort ], [0], [dnl - 192.168.0.0/24 169.254.101.2 ecmp - 192.168.0.0/24 169.254.102.2 ecmp -@@ -965,24 +1000,24 @@ AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 | - ]) - - # Test static routes from lr12 rtbs rtb1,rtb2,rtb3 were learned to lr11 --AT_CHECK([ovn_as az1 ovn-nbctl --route-table=rtb1 lr-route-list lr11], [0], [dnl -+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl --route-table=rtb1 lr-route-list lr11], [0], [dnl - IPv4 Routes - Route Table rtb1: - 10.10.10.0/24 169.254.101.2 dst-ip (learned) - ]) --AT_CHECK([ovn_as az1 ovn-nbctl --route-table=rtb2 lr-route-list lr11], [0], [dnl -+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl --route-table=rtb2 lr-route-list lr11], [0], [dnl - IPv4 Routes - Route Table rtb2: - 10.10.10.0/24 169.254.102.2 dst-ip (learned) - ]) --AT_CHECK([ovn_as az1 ovn-nbctl --route-table=rtb3 lr-route-list lr11], [0], [dnl -+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl --route-table=rtb3 lr-route-list lr11], [0], [dnl - IPv4 Routes - Route Table rtb3: - 10.10.10.0/24 169.254.103.2 dst-ip (learned) - ]) - - # Test routes from lr12 didn't leak as learned to lr21 --AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr21 | grep 192.168 | sort], [0], [dnl -+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr21 | grep 192.168 | sort], [0], [dnl - 192.168.0.0/24 169.254.101.2 dst-ip (learned) ecmp - 192.168.0.0/24 169.254.102.2 dst-ip (learned) ecmp - ]) -@@ -1035,6 +1070,7 @@ for i in 1 2; do - for j in 1 2 3; do - ts=ts1$j - ovn-ic-nbctl --may-exist ts-add $ts -+ OVS_WAIT_UNTIL([ovn-nbctl show | grep switch | grep $ts]) - - lrp=lrp-$lr-$ts - lsp=lsp-$ts-$lr -@@ -1060,6 +1096,7 @@ for i in 1 2; do - for j in 1 2; do - ts=ts2$j - ovn-ic-nbctl --may-exist ts-add $ts -+ OVS_WAIT_UNTIL([ovn-nbctl show | grep switch | grep $ts]) - - lrp=lrp-$lr-$ts - lsp=lsp-$ts-$lr -@@ -1083,6 +1120,7 @@ ovn_as az2 ovn-nbctl --route-table=rtb3 lr-route-add lr12 2001:db8:aaaa::/64 200 - ovn_as az2 ovn-nbctl --wait=sb lrp-add lr22 lrp-lr22 aa:aa:aa:aa:bb:01 "2001:db8:200::1/64" - - # Test direct routes from lr12 were learned to lr11 -+OVS_WAIT_UNTIL([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 2001:db8:3::2]) - AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 2001:db8:200 | - grep learned | awk '{print $1, $2, $5}' | sort], [0], [dnl - 2001:db8:200::/64 2001:db8:1::2 ecmp -@@ -1091,16 +1129,19 @@ AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 2001:db8:200 | - ]) - - # Test static routes from lr12 rtbs rtb1,rtb2,rtb3 were learned to lr11 -+OVS_WAIT_UNTIL([ovn_as az1 ovn-nbctl --route-table=rtb1 lr-route-list lr11 | grep learned]) - AT_CHECK([ovn_as az1 ovn-nbctl --route-table=rtb1 lr-route-list lr11], [0], [dnl - IPv6 Routes - Route Table rtb1: - 2001:db8:aaaa::/64 2001:db8:1::2 dst-ip (learned) - ]) -+OVS_WAIT_UNTIL([ovn_as az1 ovn-nbctl --route-table=rtb2 lr-route-list lr11 | grep learned]) - AT_CHECK([ovn_as az1 ovn-nbctl --route-table=rtb2 lr-route-list lr11], [0], [dnl - IPv6 Routes - Route Table rtb2: - 2001:db8:aaaa::/64 2001:db8:2::2 dst-ip (learned) - ]) -+OVS_WAIT_UNTIL([ovn_as az1 ovn-nbctl --route-table=rtb3 lr-route-list lr11 | grep learned]) - AT_CHECK([ovn_as az1 ovn-nbctl --route-table=rtb3 lr-route-list lr11], [0], [dnl - IPv6 Routes - Route Table rtb3: -@@ -1108,6 +1149,7 @@ Route Table rtb3: - ]) - - # Test routes from lr12 didn't leak as learned to lr21 -+OVS_WAIT_UNTIL([ovn_as az1 ovn-nbctl lr-route-list lr21 | grep "2001:db8:2::2" | grep learned]) - AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr21 | grep 2001 | sort], [0], [dnl - 2001:db8:200::/64 2001:db8:1::2 dst-ip (learned) ecmp - 2001:db8:200::/64 2001:db8:2::2 dst-ip (learned) ecmp -@@ -1127,6 +1169,7 @@ ovn-ic-nbctl ts-add ts1 - for i in 1 2; do - ovn_start az$i - ovn_as az$i -+ OVS_WAIT_UNTIL([ovn-nbctl show | grep switch | grep ts1]) - - # Enable route learning at AZ level - ovn-nbctl set nb_global . options:ic-route-learn=true -@@ -1152,13 +1195,13 @@ for i in 1 2; do - check ovn-nbctl --wait=sb lr-route-add $lr 0.0.0.0/0 192.168.$i.11 - done - --AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep dst-ip | sort], [0], [dnl -+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep dst-ip | sort] , [0], [dnl - 0.0.0.0/0 192.168.1.11 dst-ip - 10.0.0.0/24 192.168.1.10 dst-ip - 192.168.2.0/24 169.254.100.2 dst-ip (learned) - ]) - --AT_CHECK([ovn_as az2 ovn-nbctl lr-route-list lr12 | grep dst-ip | sort], [0], [dnl -+OVS_WAIT_FOR_OUTPUT([ovn_as az2 ovn-nbctl lr-route-list lr12 | grep dst-ip | sort], [0], [dnl - 0.0.0.0/0 192.168.2.11 dst-ip - 10.0.0.0/24 192.168.2.10 dst-ip - 192.168.1.0/24 169.254.100.1 dst-ip (learned) -@@ -1191,10 +1234,10 @@ done - # each LR has one connected subnet except TS port - - --# create lr11, lr21, lr22, ts1 and connect them --ovn-ic-nbctl ts-add ts1 -+# create lr11, lr21, lr22 and connect them - - ovn_as az1 -+OVS_WAIT_UNTIL([ovn-nbctl show | grep switch | grep ts1]) - - lr=lr11 - ovn-nbctl lr-add $lr -@@ -1209,6 +1252,7 @@ ovn-nbctl lsp-add ts1 $lsp \ - -- lsp-set-options $lsp router-port=$lrp - - ovn_as az2 -+OVS_WAIT_UNTIL([ovn-nbctl show | grep switch | grep ts1]) - for i in 1 2; do - lr=lr2$i - ovn-nbctl lr-add $lr -@@ -1230,7 +1274,7 @@ ovn_as az2 ovn-nbctl lrp-add lr21 lrp-lr21 aa:aa:aa:aa:bc:01 "192.168.1.1/24" - ovn_as az2 ovn-nbctl lrp-add lr22 lrp-lr22 aa:aa:aa:aa:bc:02 "192.168.2.1/24" - - # Test direct routes from lr21 and lr22 were learned to lr11 --AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 | -+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 | - grep learned | awk '{print $1, $2}' | sort ], [0], [dnl - 192.168.1.0/24 169.254.10.21 - 192.168.2.0/24 169.254.10.22 -@@ -1254,3 +1298,102 @@ OVN_CLEANUP_IC([az1], [az2]) - - AT_CLEANUP - ]) -+ -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([ovn-ic -- route sync -- IPv6 blacklist filter]) -+AT_KEYWORDS([IPv6-route-sync-blacklist]) -+ -+ovn_init_ic_db -+check ovn-ic-nbctl ts-add ts1 -+ -+for i in 1 2; do -+ ovn_start az$i -+ ovn_as az$i -+ -+ # Enable route learning at AZ level -+ check ovn-nbctl set nb_global . options:ic-route-learn=true -+ # Enable route advertising at AZ level -+ check ovn-nbctl set nb_global . options:ic-route-adv=true -+ # Enable blacklist single filter for IPv6 -+ check ovn-nbctl set nb_global . options:ic-route-blacklist=" \ -+ 2003:db8:1::/64,2004:aaaa::/32,2005:1234::/21" -+ -+ OVS_WAIT_UNTIL([ovn-nbctl show | grep ts1]) -+ -+ # Create LRP and connect to TS -+ check ovn-nbctl lr-add lr$i -+ check ovn-nbctl lrp-add lr$i lrp-lr$i-ts1 aa:aa:aa:aa:aa:0$i \ -+ 2001:db8:1::$i/64 -+ check ovn-nbctl lsp-add ts1 lsp-ts1-lr$i \ -+ -- lsp-set-addresses lsp-ts1-lr$i router \ -+ -- lsp-set-type lsp-ts1-lr$i router \ -+ -- lsp-set-options lsp-ts1-lr$i router-port=lrp-lr$i-ts1 -+ -+ check ovn-nbctl lrp-add lr$i lrp-lr$i-p$i 00:00:00:00:00:0$i \ -+ 2002:db8:1::$i/64 -+ -+ # Create blacklisted LRPs and connect to TS -+ check ovn-nbctl lrp-add lr$i lrp-lr$i-p-ext$i \ -+ 11:11:11:11:11:1$i 2003:db8:1::$i/64 -+ -+ check ovn-nbctl lrp-add lr$i lrp-lr$i-p-ext2$i \ -+ 22:22:22:22:22:2$i 2004:aaaa:bbb::$i/48 -+ -+ # filtered by 2005:1234::/21 - (2005:1000: - 2005:17ff:) -+ check ovn-nbctl lrp-add lr$i lrp-lr$i-p-ext3$i \ -+ 33:33:33:33:33:3$i 2005:1734:5678::$i/50 -+ -+ # additional not filtered prefix -> different subnet bits -+ check ovn-nbctl lrp-add lr$i lrp-lr$i-p-ext4$i \ -+ 44:44:44:44:44:4$i 2005:1834:5678::$i/50 -+done -+ -+for i in 1 2; do -+ OVS_WAIT_UNTIL([ovn_as az$i ovn-nbctl lr-route-list lr$i | grep learned]) -+done -+ -+AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr1 | -+ awk '/learned/{print $1, $2}' ], [0], [dnl -+2002:db8:1::/64 2001:db8:1::2 -+2005:1834:5678::/50 2001:db8:1::2 -+]) -+ -+for i in 1 2; do -+ ovn_as az$i -+ -+ # Drop blacklist -+ check ovn-nbctl remove nb_global . options ic-route-blacklist -+done -+ -+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr1 | -+ awk '/learned/{print $1, $2}' | sort ], [0], [dnl -+2002:db8:1::/64 2001:db8:1::2 -+2003:db8:1::/64 2001:db8:1::2 -+2004:aaaa:bbb::/48 2001:db8:1::2 -+2005:1734:5678::/50 2001:db8:1::2 -+2005:1834:5678::/50 2001:db8:1::2 -+]) -+ -+for i in 1 2; do -+ ovn_as az$i -+ -+ check ovn-nbctl set nb_global . \ -+ options:ic-route-blacklist="2003:db8:1::/64,2004:db8:1::/64" -+ -+ # Create an 'extra' blacklisted LRP and connect to TS -+ check ovn-nbctl lrp-add lr$i lrp-lr$i-p-ext5$i \ -+ 55:55:55:55:55:5$i 2004:db8:1::$i/64 -+done -+ -+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr1 | -+ awk '/learned/{print $1, $2}' | sort ], [0], [dnl -+2002:db8:1::/64 2001:db8:1::2 -+2004:aaaa:bbb::/48 2001:db8:1::2 -+2005:1734:5678::/50 2001:db8:1::2 -+2005:1834:5678::/50 2001:db8:1::2 -+]) -+ -+OVN_CLEANUP_IC([az1], [az2]) -+ -+AT_CLEANUP -+]) -diff --git a/tests/ovn-ipsec.at b/tests/ovn-ipsec.at -index 10ef97878..f8df8d60e 100644 ---- a/tests/ovn-ipsec.at -+++ b/tests/ovn-ipsec.at -@@ -48,11 +48,11 @@ ovn-nbctl set nb_global . options:ipsec_encapsulation=true - - check ovn-nbctl --wait=hv sync - --AT_CHECK([as hv2 ovs-vsctl get Interface ovn-hv1-0 options:remote_ip | tr -d '"\n'], [0], [192.168.0.1]) -+OVS_WAIT_UNTIL([test x`as hv2 ovs-vsctl get Interface ovn-hv1-0 options:remote_ip | tr -d '"\n'` = x192.168.0.1]) - AT_CHECK([as hv2 ovs-vsctl get Interface ovn-hv1-0 options:local_ip | tr -d '"\n'], [0], [192.168.0.2]) - AT_CHECK([as hv2 ovs-vsctl get Interface ovn-hv1-0 options:remote_name | tr -d '\n'], [0], [hv1]) - AT_CHECK([as hv2 ovs-vsctl get Interface ovn-hv1-0 options:ipsec_encapsulation | tr -d '\n'], [0], [yes]) --AT_CHECK([as hv1 ovs-vsctl get Interface ovn-hv2-0 options:remote_ip | tr -d '"\n'], [0], [192.168.0.2]) -+OVS_WAIT_UNTIL([test x`as hv1 ovs-vsctl get Interface ovn-hv2-0 options:remote_ip | tr -d '"\n'` = x192.168.0.2]) - AT_CHECK([as hv1 ovs-vsctl get Interface ovn-hv2-0 options:local_ip | tr -d '"\n'], [0], [192.168.0.1]) - AT_CHECK([as hv1 ovs-vsctl get Interface ovn-hv2-0 options:remote_name | tr -d '\n'], [0], [hv2]) - AT_CHECK([as hv1 ovs-vsctl get Interface ovn-hv2-0 options:ipsec_encapsulation | tr -d '\n'], [0], [yes]) -diff --git a/tests/ovn-macros.at b/tests/ovn-macros.at -index 13d5dc3d4..a5a3e87fd 100644 ---- a/tests/ovn-macros.at -+++ b/tests/ovn-macros.at -@@ -188,16 +188,16 @@ ovn_start_northd() { - # ovn-sbctl and ovn-nbctl use them by default, and starts ovn-northd running - # against them. - # --# Normally this starts an active northd and a backup northd. The following -+# Normally this starts only an active northd and no backup northd. The following - # options are accepted to adjust that: --# --backup-northd=none Don't start a backup northd. -+# --backup-northd Start a backup northd. - # --backup-northd=paused Start the backup northd in the paused state. - ovn_start () { -- local backup_northd=: -+ local backup_northd=false - local backup_northd_options= - case $1 in -- --backup-northd=none) backup_northd=false; shift ;; -- --backup-northd=paused) backup_northd_options=--paused; shift ;; -+ --backup-northd) backup_northd=true; shift ;; -+ --backup-northd=paused) backup_northd=true; backup_northd_options=--paused; shift ;; - esac - local AZ=$1 - local msg_prefix=${AZ:+$AZ: } -@@ -288,11 +288,44 @@ net_attach () { - || return 1 - } - -+ovn_wait_for_encaps() { -+ local systemid=$1 -+ -+ if [[ -f "${OVN_SYSCONFDIR}/system-id-override" ]]; then -+ systemid=$(cat ${OVN_SYSCONFDIR}/system-id-override) -+ fi -+ -+ local encap=$(ovs-vsctl get Open_vSwitch . external_ids:ovn-encap-type-$systemid) -+ if [[ -z "$encap" ]]; then -+ encap=$(ovs-vsctl get Open_vSwitch . external_ids:ovn-encap-type) -+ fi -+ encap=$(tr -d '"' <<< $encap) -+ -+ local ip=$(ovs-vsctl get Open_vSwitch . external_ids:ovn-encap-ip-$systemid) -+ if [[ -z "$ip" ]]; then -+ ip=$(ovs-vsctl get Open_vSwitch . external_ids:ovn-encap-ip) -+ fi -+ ip=$(tr -d '"' <<< $ip) -+ -+ IFS="," read -r -a encap_types <<< "$encap" -+ for e in "${encap_types[[@]]}"; do -+ wait_column "$ip" sb:Encap ip chassis_name="$systemid" type="$e" -+ done -+} -+ - # ovn_az_attach AZ NETWORK BRIDGE IP [MASKLEN] [ENCAP] - ovn_az_attach() { -- local az=$1 net=$2 bridge=$3 ip=$4 masklen=${5-24} encap=${6-geneve,vxlan} systemid=${7-$sandbox} cli_args=${@:8} -+ local az=$1 net=$2 bridge=$3 ip=$4 masklen=${5-24} encap=${6-geneve,vxlan} -+ local systemid=${7-$sandbox} systemid_override=$8 - net_attach $net $bridge || return 1 - -+ local expected_encap_id=$systemid -+ local cli_args="" -+ if [[ -n "$systemid_override" ]]; then -+ cli_args="-n $systemid_override" -+ expected_encap_id=$systemid_override -+ fi -+ - mac=`ovs-vsctl get Interface $bridge mac_in_use | sed s/\"//g` - arp_table="$arp_table $sandbox,$bridge,$ip,$mac" - if test -z $(echo $ip | sed '/:/d'); then -@@ -332,6 +365,11 @@ ovn_az_attach() { - fi - - start_daemon ovn-controller --enable-dummy-vif-plug ${cli_args} || return 1 -+ if test X"$az" = XNONE; then -+ ovn_wait_for_encaps $expected_encap_id -+ else -+ ovn_as $az ovn_wait_for_encaps $expected_encap_id -+ fi - } - - # ovn_attach NETWORK BRIDGE IP [MASKLEN] [ENCAP] -@@ -372,6 +410,7 @@ start_virtual_controller() { - || return 1 - - ovn-controller --enable-dummy-vif-plug ${cli_args} -vconsole:off --detach --no-chdir -+ ovn_wait_for_encaps $systemid - } - - # ovn_setenv AZ -@@ -833,15 +872,40 @@ ovn_trace_client() { - # ovs-appctl netdev-dummy/receive $vif $packet - # - fmt_pkt() { -- echo "from scapy.all import *; \ -- import binascii; \ -- out = binascii.hexlify(raw($1)); \ -- print(out.decode())" | $PYTHON3 -+ ctlfile=$ovs_base/scapy.ctl -+ if [[ ! -S $ctlfile ]]; then -+ start_scapy_server -+ fi -+ while [[ ! -S $ctlfile ]]; do sleep 0.1; done -+ ovs-appctl -t $ctlfile payload "$1" -+} -+ -+start_scapy_server() { -+ pidfile=$ovs_base/scapy.pid -+ ctlfile=$ovs_base/scapy.ctl -+ logfile=$ovs_base/scapy.log -+ lockfile=$ovs_base/scapy.lock -+ -+ flock -n $lockfile "$top_srcdir"/tests/scapy-server.py \ -+ --pidfile=$pidfile --unixctl=$ctlfile --log-file=$logfile --detach \ -+ && on_exit "test -e \"$pidfile\" && ovs-appctl -t $ctlfile exit" -+} -+ -+sleep_northd() { -+ echo Northd going to sleep -+ AT_CHECK([kill -STOP $(cat northd/ovn-northd.pid)]) -+ on_exit "kill -CONT $(cat northd/ovn-northd.pid)" -+} -+ -+wake_up_northd() { -+ echo Northd waking up -+ AT_CHECK([kill -CONT $(cat northd/ovn-northd.pid)]) - } - - sleep_sb() { - echo SB going to sleep - AT_CHECK([kill -STOP $(cat ovn-sb/ovsdb-server.pid)]) -+ on_exit "kill -CONT $(cat ovn-sb/ovsdb-server.pid)" - } - wake_up_sb() { - echo SB waking up -@@ -865,6 +929,7 @@ sleep_ovs() { - hv=$1 - echo ovs $hv going to sleep - AT_CHECK([kill -STOP $(cat $hv/ovs-vswitchd.pid)]) -+ on_exit "kill -CONT $(cat $hv/ovs-vswitchd.pid)" - } - - wake_up_ovs() { -@@ -876,12 +941,17 @@ wake_up_ovs() { - sleep_ovsdb() { - echo OVSDB $1 going to sleep - AT_CHECK([kill -STOP $(cat $1/ovsdb-server.pid)]) -+ on_exit "kill -CONT $(cat $1/ovsdb-server.pid)" - } - wake_up_ovsdb() { - echo OVSDB $1 waking up - AT_CHECK([kill -CONT $(cat $1/ovsdb-server.pid)]) - } - -+trim_zeros() { -+ sed 's/\(00\)\{1,\}$//' -+} -+ - OVS_END_SHELL_HELPERS - - m4_define([OVN_POPULATE_ARP], [AT_CHECK(ovn_populate_arp__, [0], [ignore])]) -@@ -913,3 +983,9 @@ m4_define([RUN_OVN_NBCTL], [ - check ovn-nbctl ${command} - unset command - ]) -+ -+m4_define([OVN_CHECK_SCAPY_EDNS_CLIENT_SUBNET_SUPPORT], -+[ -+ AT_SKIP_IF([test $HAVE_SCAPY = no]) -+ AT_SKIP_IF([! echo "from scapy.layers.dns import EDNS0ClientSubnet" | python 2>&1 > /dev/null]) -+]) -diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at -index fde3a28ee..94641f2f0 100644 ---- a/tests/ovn-nbctl.at -+++ b/tests/ovn-nbctl.at -@@ -2695,7 +2695,9 @@ dnl --------------------------------------------------------------------- - - AT_SETUP([ovn-nbctl - daemon retry connection]) - OVN_NBCTL_TEST_START daemon --AT_CHECK([kill `cat ovsdb-server.pid`]) -+pid=$(cat ovsdb-server.pid) -+AT_CHECK([kill $pid]) -+OVS_WAIT_WHILE([kill -0 $pid 2>/dev/null]) - AT_CHECK([ovsdb-server --detach --no-chdir --pidfile --log-file --remote=punix:$OVS_RUNDIR/ovnnb_db.sock ovn-nb.db], [0], [], [stderr]) - AT_CHECK([ovn-nbctl show], [0], [ignore]) - OVN_NBCTL_TEST_STOP "/terminating with signal 15/d" -diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at -index 65d3f4b03..7add1aa57 100644 ---- a/tests/ovn-northd.at -+++ b/tests/ovn-northd.at -@@ -20,6 +20,14 @@ m4_define([_DUMP_DB_TABLES], [ - # sure nothing is changed by the recompute. It is used for ensuring the - # correctness of incremental processing. - m4_define([CHECK_NO_CHANGE_AFTER_RECOMPUTE], [ -+ wait_port_up=$1 -+ if test X$wait_port_up = X1; then -+ # Wait for hv to have received all previous commands -+ # Make sure ports are up as otherwise it might come as a difference after recompute -+ echo "waiting for ports up" -+ check ovn-nbctl --wait=hv sync -+ wait_for_ports_up -+ fi - _DUMP_DB_TABLES(before) - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/recompute - check ovn-nbctl --wait=sb sync -@@ -813,7 +821,7 @@ AT_CLEANUP - - OVN_FOR_EACH_NORTHD_NO_HV([ - AT_SETUP([ovn-northd restart]) --ovn_start --backup-northd=none -+ovn_start - - # Check that ovn-northd is active, by verifying that it creates and - # destroys southbound datapaths as one would expect. -@@ -832,7 +840,7 @@ sleep 5 - check_row_count Datapath_Binding 1 - - # Now resume ovn-northd. Changes should catch up. --ovn_start_northd primary -+ovn_start_northd - wait_row_count Datapath_Binding 2 - - AT_CLEANUP -@@ -841,7 +849,7 @@ AT_CLEANUP - OVN_FOR_EACH_NORTHD_NO_HV([ - AT_SETUP([northbound database reconnection]) - --ovn_start --backup-northd=none -+ovn_start - - # Check that ovn-northd is active, by verifying that it creates and - # destroys southbound datapaths as one would expect. -@@ -873,7 +881,7 @@ AT_CLEANUP - OVN_FOR_EACH_NORTHD_NO_HV([ - AT_SETUP([southbound database reconnection]) - --ovn_start --backup-northd=none -+ovn_start - - # Check that ovn-northd is active, by verifying that it creates and - # destroys southbound datapaths as one would expect. -@@ -1100,7 +1108,7 @@ AT_CAPTURE_FILE([crflows]) - AT_CHECK([grep -e "lr_out_snat" drflows | sed 's/table=../table=??/' | sort], [0], [dnl - table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) - table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) -- table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst == $allowed_range), action=(ct_snat(172.16.1.1);) -+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);) - ]) - - AT_CHECK([grep -e "lr_out_snat" crflows | sed 's/table=../table=??/' | sort], [0], [dnl -@@ -1130,7 +1138,7 @@ AT_CAPTURE_FILE([crflows2]) - AT_CHECK([grep -e "lr_out_snat" drflows2 | sed 's/table=../table=??/' | sort], [0], [dnl - table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) - table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) -- table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1")), action=(ct_snat(172.16.1.1);) -+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);) - table=??(lr_out_snat ), priority=163 , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst == $disallowed_range), action=(next;) - ]) - -@@ -1159,7 +1167,7 @@ AT_CAPTURE_FILE([crflows2]) - AT_CHECK([grep -e "lr_out_snat" drflows3 | sed 's/table=../table=??/' | sort], [0], [dnl - table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) - table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) -- table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst == $allowed_range), action=(ct_snat(172.16.1.2);) -+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst == $allowed_range && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);) - ]) - - AT_CHECK([grep -e "lr_out_snat" crflows3 | sed 's/table=../table=??/' | sort], [0], [dnl -@@ -1186,7 +1194,7 @@ AT_CAPTURE_FILE([crflows2]) - AT_CHECK([grep -e "lr_out_snat" drflows4 | sed 's/table=../table=??/' | sort], [0], [dnl - table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) - table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) -- table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1")), action=(ct_snat(172.16.1.2);) -+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);) - table=??(lr_out_snat ), priority=163 , match=(ip && ip4.src == 50.0.0.11 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && ip4.dst == $disallowed_range), action=(next;) - ]) - -@@ -1554,9 +1562,6 @@ AT_CAPTURE_FILE([sbflows]) - # dnat_and_snat or snat entry. - AT_CHECK([grep "lr_in_unsnat" sbflows | sort], [0], [dnl - table=4 (lr_in_unsnat ), priority=0 , match=(1), action=(next;) -- table=4 (lr_in_unsnat ), priority=120 , match=(ip4 && ip4.dst == 192.168.2.1 && tcp && tcp.dst == 8080), action=(next;) -- table=4 (lr_in_unsnat ), priority=120 , match=(ip4 && ip4.dst == 192.168.2.4 && udp && udp.dst == 8080), action=(next;) -- table=4 (lr_in_unsnat ), priority=120 , match=(ip4 && ip4.dst == 192.168.2.5 && tcp && tcp.dst == 8080), action=(next;) - table=4 (lr_in_unsnat ), priority=90 , match=(ip && ip4.dst == 192.168.2.1), action=(ct_snat;) - table=4 (lr_in_unsnat ), priority=90 , match=(ip && ip4.dst == 192.168.2.4), action=(ct_snat;) - ]) -@@ -1587,9 +1592,6 @@ AT_CAPTURE_FILE([sbflows]) - # dnat_and_snat or snat entry. - AT_CHECK([grep "lr_in_unsnat" sbflows | sort], [0], [dnl - table=4 (lr_in_unsnat ), priority=0 , match=(1), action=(next;) -- table=4 (lr_in_unsnat ), priority=120 , match=(ip4 && ip4.dst == 192.168.2.1 && tcp && tcp.dst == 8080), action=(next;) -- table=4 (lr_in_unsnat ), priority=120 , match=(ip4 && ip4.dst == 192.168.2.4 && udp && udp.dst == 8080), action=(next;) -- table=4 (lr_in_unsnat ), priority=120 , match=(ip4 && ip4.dst == 192.168.2.5 && tcp && tcp.dst == 8080), action=(next;) - table=4 (lr_in_unsnat ), priority=90 , match=(ip && ip4.dst == 192.168.2.1), action=(ct_snat;) - table=4 (lr_in_unsnat ), priority=90 , match=(ip && ip4.dst == 192.168.2.4), action=(ct_snat;) - ]) -@@ -2376,6 +2378,24 @@ check_acl_lflow acl_two meter_me__${acl2} sw0 - check_acl_lflow acl_three meter_me__${acl3} sw0 - check_acl_lflow acl_three meter_me__${acl3} sw1 - -+AS_BOX([Disable/enable logging for acl3 while still referencing the meter]) -+check_row_count meter 4 -+check ovn-nbctl --wait=sb set acl $acl3 log=false -+check_row_count meter 3 -+check_meter_by_name meter_me meter_me__${acl1} meter_me__${acl2} -+check_meter_by_name NOT meter_me__${acl3} -+check_acl_lflow acl_one meter_me__${acl1} sw0 -+check_acl_lflow acl_two meter_me__${acl2} sw0 -+ -+check ovn-nbctl --wait=sb set acl $acl3 log=true -+check_row_count meter 4 -+check_meter_by_name \ -+ meter_me meter_me__${acl1} meter_me__${acl2} meter_me__${acl3} -+check_acl_lflow acl_one meter_me__${acl1} sw0 -+check_acl_lflow acl_two meter_me__${acl2} sw0 -+check_acl_lflow acl_three meter_me__${acl3} sw0 -+check_acl_lflow acl_three meter_me__${acl3} sw1 -+ - AS_BOX([Stop using meter for acl1]) - check ovn-nbctl --wait=sb clear acl $acl1 meter - check_meter_by_name meter_me meter_me__${acl2} -@@ -2860,7 +2880,7 @@ lbg0_uuid=$(fetch_column sb:load_balancer _uuid name=lbg0) - echo - echo "__file__:__line__: Check that SB lb0 has sw0 in datapaths column." - --lb0_dp_group=$(fetch_column sb:load_balancer datapath_group name=lb0) -+lb0_dp_group=$(fetch_column sb:load_balancer ls_datapath_group name=lb0) - AT_CHECK_UNQUOTED([ovn-sbctl --bare --columns _uuid,datapaths find Logical_DP_Group dnl - | grep -A1 $lb0_dp_group | tail -1], [0], [dnl - $sw0_sb_uuid -@@ -2871,7 +2891,7 @@ check_column "" sb:datapath_binding load_balancers external_ids:name=sw0 - echo - echo "__file__:__line__: Check that SB lbg0 has sw0 in datapaths column." - --lbg0_dp_group=$(fetch_column sb:load_balancer datapath_group name=lbg0) -+lbg0_dp_group=$(fetch_column sb:load_balancer ls_datapath_group name=lbg0) - AT_CHECK_UNQUOTED([ovn-sbctl --bare --columns _uuid,datapaths find Logical_DP_Group dnl - | grep -A1 $lbg0_dp_group | tail -1], [0], [dnl - $sw0_sb_uuid -@@ -2897,6 +2917,15 @@ sb:load_balancer vips,protocol name=lbg0 - - check ovn-nbctl lr-add lr0 -- add logical_router lr0 load_balancer_group $lbg - check ovn-nbctl --wait=sb lr-lb-add lr0 lb0 -+check_row_count sb:load_balancer 2 -+ -+lr0_sb_uuid=$(fetch_column datapath_binding _uuid external_ids:name=lr0) -+lb0_lr_dp_group=$(fetch_column sb:load_balancer lr_datapath_group name=lb0) -+ -+AT_CHECK_UNQUOTED([ovn-sbctl --bare --columns _uuid,datapaths find Logical_DP_Group dnl -+ | grep -A1 $lb0_lr_dp_group | tail -1], [0], [dnl -+$lr0_sb_uuid -+]) - - echo - echo "__file__:__line__: Check that SB lb0 has only sw0 in datapaths column." -@@ -2942,7 +2971,13 @@ check_row_count sb:load_balancer 2 - lbg1=$(fetch_column nb:load_balancer _uuid name=lbg1) - check ovn-nbctl add load_balancer_group $lbg load_balancer $lbg1 - check ovn-nbctl --wait=sb lr-lb-add lr0 lb1 --check_row_count sb:load_balancer 3 -+check_row_count sb:load_balancer 4 -+ -+lb1_lr_dp_group=$(fetch_column sb:load_balancer lr_datapath_group name=lb1) -+AT_CHECK_UNQUOTED([ovn-sbctl --bare --columns _uuid,datapaths find Logical_DP_Group dnl -+ | grep -A1 $lb1_lr_dp_group | tail -1], [0], [dnl -+$lr0_sb_uuid -+]) - - echo - echo "__file__:__line__: Associate lb1 to sw1 and check that lb1 is created in SB DB." -@@ -2959,7 +2994,7 @@ echo "__file__:__line__: Check that SB lbg1 has vips and protocol columns are se - check_column "20.0.0.30:80=20.0.0.50:8080 udp" sb:load_balancer vips,protocol name=lbg1 - - lb1_uuid=$(fetch_column sb:load_balancer _uuid name=lb1) --lb1_dp_group=$(fetch_column sb:load_balancer datapath_group name=lb1) -+lb1_dp_group=$(fetch_column sb:load_balancer ls_datapath_group name=lb1) - - echo - echo "__file__:__line__: Check that SB lb1 has sw1 in datapaths column." -@@ -2970,7 +3005,7 @@ $sw1_sb_uuid - ]) - - lbg1_uuid=$(fetch_column sb:load_balancer _uuid name=lbg1) --lbg1_dp_group=$(fetch_column sb:load_balancer datapath_group name=lbg1) -+lbg1_dp_group=$(fetch_column sb:load_balancer ls_datapath_group name=lbg1) - - echo - echo "__file__:__line__: Check that SB lbg1 has sw0 and sw1 in datapaths column." -@@ -4596,7 +4631,7 @@ AT_SKIP_IF([test "$HAVE_OPENSSL" = no]) - PKIDIR="$(cd $abs_top_builddir/tests && pwd)" - AT_SKIP_IF([expr "$PKIDIR" : ".*[[ '\" - \\]]"]) --ovn_start --backup-northd=none -+ovn_start - - as northd - OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE]) -@@ -5095,6 +5130,7 @@ AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | sed 's/table=../table=??/' | sort], - table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;) - table=??(ls_in_l2_lkup ), priority=75 , match=(eth.src == {00:00:00:00:01:01} && (arp.op == 1 || rarp.op == 3 || nd_ns)), action=(outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 10.0.0.100), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) -+ table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 10.0.0.200), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 192.168.1.1), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - ]) -@@ -5109,6 +5145,7 @@ AT_CHECK([grep "ls_in_l2_lkup" ls2_lflows | sed 's/table=../table=??/' | sort], - table=??(ls_in_l2_lkup ), priority=75 , match=(eth.src == {00:00:00:00:02:01} && (arp.op == 1 || rarp.op == 3 || nd_ns)), action=(outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 192.168.2.1), action=(clone {outport = "ls2-ro2"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 20.0.0.100), action=(clone {outport = "ls2-ro2"; output; }; outport = "_MC_flood_l2"; output;) -+ table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 20.0.0.200), action=(clone {outport = "ls2-ro2"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && nd_ns && nd.target == fe80::200:ff:fe00:201), action=(clone {outport = "ls2-ro2"; output; }; outport = "_MC_flood_l2"; output;) - ]) - -@@ -5129,8 +5166,10 @@ AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | sed 's/table=../table=??/' | sort], - table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;) - table=??(ls_in_l2_lkup ), priority=75 , match=(eth.src == {00:00:00:00:01:01} && (arp.op == 1 || rarp.op == 3 || nd_ns)), action=(outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 10.0.0.100), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) -+ table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 10.0.0.200), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 192.168.1.1), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 30.0.0.100), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) -+ table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 30.0.0.200), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - ]) - -@@ -5144,7 +5183,9 @@ AT_CHECK([grep "ls_in_l2_lkup" ls2_lflows | sed 's/table=../table=??/' | sort], - table=??(ls_in_l2_lkup ), priority=75 , match=(eth.src == {00:00:00:00:02:01} && (arp.op == 1 || rarp.op == 3 || nd_ns)), action=(outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 192.168.2.1), action=(clone {outport = "ls2-ro2"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 20.0.0.100), action=(clone {outport = "ls2-ro2"; output; }; outport = "_MC_flood_l2"; output;) -+ table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 20.0.0.200), action=(clone {outport = "ls2-ro2"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 40.0.0.100), action=(clone {outport = "ls2-ro2"; output; }; outport = "_MC_flood_l2"; output;) -+ table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 40.0.0.200), action=(clone {outport = "ls2-ro2"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && nd_ns && nd.target == fe80::200:ff:fe00:201), action=(clone {outport = "ls2-ro2"; output; }; outport = "_MC_flood_l2"; output;) - ]) - -@@ -5162,9 +5203,11 @@ AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | sed 's/table=../table=??/' | sort], - table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;) - table=??(ls_in_l2_lkup ), priority=75 , match=(eth.src == {00:00:00:00:01:01} && (arp.op == 1 || rarp.op == 3 || nd_ns)), action=(outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 10.0.0.100), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) -+ table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 10.0.0.200), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 192.168.1.1), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 192.168.1.100), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 30.0.0.100), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) -+ table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 30.0.0.200), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - ]) - -@@ -5180,9 +5223,11 @@ AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | sed 's/table=../table=??/' | sort], - table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;) - table=??(ls_in_l2_lkup ), priority=75 , match=(eth.src == {00:00:00:00:01:01} && (arp.op == 1 || rarp.op == 3 || nd_ns)), action=(outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 10.0.0.100), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) -+ table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 10.0.0.200), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 192.168.1.1), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 192.168.1.100), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 30.0.0.100), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) -+ table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 30.0.0.200), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - ]) - -@@ -5204,9 +5249,11 @@ AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | sed 's/table=../table=??/' | sort], - table=??(ls_in_l2_lkup ), priority=70 , match=(eth.mcast), action=(outport = "_MC_flood"; output;) - table=??(ls_in_l2_lkup ), priority=75 , match=(eth.src == {00:00:00:00:01:01} && (arp.op == 1 || rarp.op == 3 || nd_ns)), action=(outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 10.0.0.100), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) -+ table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 10.0.0.200), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 192.168.1.1), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 192.168.1.100), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 30.0.0.100), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) -+ table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && arp.op == 1 && arp.tpa == 30.0.0.200), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - table=??(ls_in_l2_lkup ), priority=80 , match=(flags[[1]] == 0 && nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_flood_l2"; output;) - ]) - -@@ -5364,12 +5411,12 @@ AT_CHECK([grep "lr_out_post_undnat" lr0flows | sed 's/table=./table=?/' | sort], - AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl - table=? (lr_out_snat ), priority=0 , match=(1), action=(next;) - table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) -- table=? (lr_out_snat ), priority=153 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat_in_czone(172.168.0.10);) -- table=? (lr_out_snat ), priority=154 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && reg9[[4]] == 1), action=(reg9[[4]] = 0; ct_snat(172.168.0.10);) -- table=? (lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat_in_czone(172.168.0.30);) -- table=? (lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat_in_czone(172.168.0.20);) -- table=? (lr_out_snat ), priority=162 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && reg9[[4]] == 1), action=(reg9[[4]] = 0; ct_snat(172.168.0.30);) -- table=? (lr_out_snat ), priority=162 , match=(ip && ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && reg9[[4]] == 1), action=(reg9[[4]] = 0; ct_snat(172.168.0.20);) -+ table=? (lr_out_snat ), priority=153 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat_in_czone(172.168.0.10);) -+ table=? (lr_out_snat ), priority=154 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl) && reg9[[4]] == 1), action=(reg9[[4]] = 0; ct_snat(172.168.0.10);) -+ table=? (lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat_in_czone(172.168.0.30);) -+ table=? (lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat_in_czone(172.168.0.20);) -+ table=? (lr_out_snat ), priority=162 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl) && reg9[[4]] == 1), action=(reg9[[4]] = 0; ct_snat(172.168.0.30);) -+ table=? (lr_out_snat ), priority=162 , match=(ip && ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl) && reg9[[4]] == 1), action=(reg9[[4]] = 0; ct_snat(172.168.0.20);) - ]) - - # Separate zones for DGP -@@ -5412,9 +5459,9 @@ AT_CHECK([grep "lr_out_post_undnat" lr0flows | sed 's/table=./table=?/' | sort], - AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl - table=? (lr_out_snat ), priority=0 , match=(1), action=(next;) - table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) -- table=? (lr_out_snat ), priority=153 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat(172.168.0.10);) -- table=? (lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat(172.168.0.30);) -- table=? (lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat(172.168.0.20);) -+ table=? (lr_out_snat ), priority=153 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);) -+ table=? (lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);) -+ table=? (lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);) - ]) - - # Associate load balancer to lr0 -@@ -5494,12 +5541,12 @@ AT_CHECK([grep "lr_out_post_undnat" lr0flows | sed 's/table=./table=?/' | sort], - AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl - table=? (lr_out_snat ), priority=0 , match=(1), action=(next;) - table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) -- table=? (lr_out_snat ), priority=153 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat_in_czone(172.168.0.10);) -- table=? (lr_out_snat ), priority=154 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && reg9[[4]] == 1), action=(reg9[[4]] = 0; ct_snat(172.168.0.10);) -- table=? (lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat_in_czone(172.168.0.30);) -- table=? (lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat_in_czone(172.168.0.20);) -- table=? (lr_out_snat ), priority=162 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && reg9[[4]] == 1), action=(reg9[[4]] = 0; ct_snat(172.168.0.30);) -- table=? (lr_out_snat ), priority=162 , match=(ip && ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && reg9[[4]] == 1), action=(reg9[[4]] = 0; ct_snat(172.168.0.20);) -+ table=? (lr_out_snat ), priority=153 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat_in_czone(172.168.0.10);) -+ table=? (lr_out_snat ), priority=154 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl) && reg9[[4]] == 1), action=(reg9[[4]] = 0; ct_snat(172.168.0.10);) -+ table=? (lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat_in_czone(172.168.0.30);) -+ table=? (lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat_in_czone(172.168.0.20);) -+ table=? (lr_out_snat ), priority=162 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl) && reg9[[4]] == 1), action=(reg9[[4]] = 0; ct_snat(172.168.0.30);) -+ table=? (lr_out_snat ), priority=162 , match=(ip && ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl) && reg9[[4]] == 1), action=(reg9[[4]] = 0; ct_snat(172.168.0.20);) - ]) - - # Separate zones for DGP -@@ -5560,9 +5607,9 @@ AT_CHECK([grep "lr_out_post_undnat" lr0flows | sed 's/table=./table=?/' | sort], - AT_CHECK([grep "lr_out_snat" lr0flows | sed 's/table=./table=?/' | sort], [0], [dnl - table=? (lr_out_snat ), priority=0 , match=(1), action=(next;) - table=? (lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) -- table=? (lr_out_snat ), priority=153 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat(172.168.0.10);) -- table=? (lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat(172.168.0.30);) -- table=? (lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public")), action=(ct_snat(172.168.0.20);) -+ table=? (lr_out_snat ), priority=153 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.10);) -+ table=? (lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.10 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.30);) -+ table=? (lr_out_snat ), priority=161 , match=(ip && ip4.src == 10.0.0.3 && outport == "lr0-public" && is_chassis_resident("cr-lr0-public") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.168.0.20);) - ]) - - # Make the logical router as Gateway router -@@ -5703,7 +5750,6 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl - table=4 (lr_in_unsnat ), priority=0 , match=(1), action=(next;) - table=4 (lr_in_unsnat ), priority=110 , match=(inport == "lr0-public" && ip4.dst == 172.168.0.10), action=(ct_snat;) - table=4 (lr_in_unsnat ), priority=110 , match=(inport == "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;) -- table=4 (lr_in_unsnat ), priority=120 , match=(ip4 && ip4.dst == 172.168.0.10 && tcp && tcp.dst == 9082), action=(next;) - table=4 (lr_in_unsnat ), priority=90 , match=(ip && ip4.dst == 172.168.0.10), action=(ct_snat;) - table=4 (lr_in_unsnat ), priority=90 , match=(ip && ip4.dst == 172.168.0.20), action=(ct_snat;) - table=4 (lr_in_unsnat ), priority=90 , match=(ip && ip4.dst == 172.168.0.30), action=(ct_snat;) -@@ -5780,7 +5826,6 @@ AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl - table=4 (lr_in_unsnat ), priority=110 , match=(inport == "lr0-public" && ip6.dst == def0::10), action=(ct_snat;) - table=4 (lr_in_unsnat ), priority=110 , match=(inport == "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;) - table=4 (lr_in_unsnat ), priority=110 , match=(inport == "lr0-sw0" && ip6.dst == aef0::1), action=(ct_snat;) -- table=4 (lr_in_unsnat ), priority=120 , match=(ip4 && ip4.dst == 172.168.0.10 && tcp && tcp.dst == 9082), action=(next;) - table=4 (lr_in_unsnat ), priority=90 , match=(ip && ip4.dst == 172.168.0.10), action=(ct_snat;) - table=4 (lr_in_unsnat ), priority=90 , match=(ip && ip4.dst == 172.168.0.20), action=(ct_snat;) - table=4 (lr_in_unsnat ), priority=90 , match=(ip && ip4.dst == 172.168.0.30), action=(ct_snat;) -@@ -6019,9 +6064,9 @@ ovn_start - check ovn-nbctl ls-add ls -- lb-add lb1 10.0.0.1:80 10.0.0.2:80 -- ls-lb-add ls lb1 - check ovn-nbctl --wait=sb sync - --dps=$(fetch_column Load_Balancer datapath_group) -+dps=$(fetch_column Load_Balancer ls_datapath_group) - nlb=$(fetch_column nb:Load_Balancer _uuid) --AT_CHECK([ovn-sbctl create Load_Balancer name=lb1 datapath_group="$dps" external_ids="lb_id=$nlb"], [0], [ignore]) -+AT_CHECK([ovn-sbctl create Load_Balancer name=lb1 ls_datapath_group="$dps" external_ids="lb_id=$nlb"], [0], [ignore]) - - check ovn-nbctl --wait=sb sync - check_row_count Load_Balancer 1 -@@ -6060,7 +6105,8 @@ OVN_FOR_EACH_NORTHD_NO_HV([ - AT_SETUP([ovn -- gateway mtu check pkt larger flows]) - ovn_start - --check ovn-sbctl chassis-add ch1 geneve 127.0.0.1 -+check ovn-sbctl chassis-add ch1 geneve 127.0.0.1 --\ -+ set chassis ch1 other_config:ct-commit-nat-v2=true - - check ovn-nbctl ls-add sw0 - check ovn-nbctl ls-add sw1 -@@ -6109,6 +6155,10 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=. - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };) - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) - ]) - - AT_CHECK([grep -E "lr_in_admission.*check_pkt_larger" lr0flows | sort], [0], [dnl -@@ -6123,6 +6173,10 @@ AT_CHECK([grep -E "lr_in_ip_input.*icmp6_error" lr0flows | sort], [0], [dnl - table=3 (lr_in_ip_input ), priority=150 , match=(inport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip6.dst = ip6.src; ip6.src = fe80::200:20ff:fe20:1213; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) - ]) - -+AT_CHECK([grep -E "lr_out_post_snat.*ct_commit_nat" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl -+ table=??(lr_out_post_snat ), priority=100 , match=(icmp && flags.icmp_snat == 1), action=(ct_commit_nat(snat);) -+]) -+ - # Clear the gateway-chassis for lr0-public - check ovn-nbctl --wait=sb clear logical_router_port lr0-public gateway_chassis - -@@ -6140,6 +6194,10 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=. - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };) - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) - ]) - - AT_CHECK([grep -E "lr_in_admission.*check_pkt_larger" lr0flows | sort], [0], [dnl -@@ -6154,6 +6212,10 @@ AT_CHECK([grep -E "lr_in_ip_input.*icmp6_error" lr0flows | sort], [0], [dnl - table=3 (lr_in_ip_input ), priority=150 , match=(inport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip6.dst = ip6.src; ip6.src = fe80::200:20ff:fe20:1213; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) - ]) - -+AT_CHECK([grep -E "lr_out_post_snat.*ct_commit_nat" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl -+ table=??(lr_out_post_snat ), priority=100 , match=(icmp && flags.icmp_snat == 1), action=(ct_commit_nat(snat);) -+]) -+ - # Set gateway_mtu_bypass to avoid check_pkt_larger() for tcp on lr0-public. - check ovn-nbctl --wait=sb set logical_router_port lr0-public options:gateway_mtu_bypass=tcp - -@@ -6169,6 +6231,10 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=. - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };) - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) - ]) - - AT_CHECK([grep "lr_in_admission" lr0flows | grep -e "check_pkt_larger" -e "tcp" | sort], [0], [dnl -@@ -6198,6 +6264,14 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=. - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=0); };) - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip4.dst = ip4.src; ip4.src = 172.168.0.100; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip6.dst = ip6.src; ip6.src = fe80::200:20ff:fe20:1213; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400; next(pipeline=ingress, table=0); };) - ]) - - AT_CHECK([grep "lr_in_admission.*check_pkt_larger" lr0flows | sort], [0], [dnl -@@ -6216,6 +6290,10 @@ AT_CHECK([grep -E "lr_in_ip_input.*icmp6_error" lr0flows | sort], [0], [dnl - table=3 (lr_in_ip_input ), priority=150 , match=(inport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400; next(pipeline=ingress, table=0); };) - ]) - -+AT_CHECK([grep -E "lr_out_post_snat.*ct_commit_nat" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl -+ table=??(lr_out_post_snat ), priority=100 , match=(icmp && flags.icmp_snat == 1), action=(ct_commit_nat(snat);) -+]) -+ - # Set gateway_mtu_bypass to avoid check_pkt_larger() for tcp on lr0-sw0. - check ovn-nbctl --wait=sb set logical_router_port lr0-sw0 options:gateway_mtu_bypass=tcp - -@@ -6237,6 +6315,14 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=. - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=0); };) - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip4.dst = ip4.src; ip4.src = 172.168.0.100; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip6.dst = ip6.src; ip6.src = fe80::200:20ff:fe20:1213; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip4.dst = ip4.src; ip4.src = 10.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw0" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:01; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff01; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip4 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw1" && outport == "lr0-public" && ip6 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1500; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400; next(pipeline=ingress, table=0); };) - ]) - - AT_CHECK([grep "lr_in_admission" lr0flows | grep -e "check_pkt_larger" -e "tcp" | sort], [0], [dnl -@@ -6264,6 +6350,10 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=. - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip6.dst = ip6.src; ip6.src = fe80::200:20ff:fe20:1213; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400; next(pipeline=ingress, table=0); };) - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=0); };) - table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0), action=(icmp6_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip4.dst = ip4.src; ip4.src = 172.168.0.100; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; ip6.dst = ip6.src; ip6.src = fe80::200:20ff:fe20:1213; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp4_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip4.dst = ip4.src; ip4.src = 20.0.0.1; ip.ttl = 255; icmp4.type = 3; /* Destination Unreachable. */ icmp4.code = 4; /* Frag Needed and DF was Set. */ icmp4.frag_mtu = 1400; next(pipeline=ingress, table=0); };) -+ table=??(lr_in_larger_pkts ), priority=160 , match=(inport == "lr0-sw1" && outport == "lr0-sw0" && ip6 && reg9[[1]] && reg9[[0]] == 0 && ct.trk && ct.rpl && ct.dnat), action=(icmp6_error {flags.icmp_snat = 1; reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:00:00:ff:02; ip6.dst = ip6.src; ip6.src = fe80::200:ff:fe00:ff02; ip.ttl = 255; icmp6.type = 2; /* Packet Too Big. */ icmp6.code = 0; icmp6.frag_mtu = 1400; next(pipeline=ingress, table=0); };) - ]) - - check ovn-nbctl --wait=sb clear logical_router_port lr0-sw0 options -@@ -6296,6 +6386,12 @@ AT_CHECK([grep "lr_in_admission" lr0flows | grep -e "check_pkt_larger" | sort], - table=0 (lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1518); xreg0[[0..47]] = 00:00:20:20:12:13; next;) - ]) - -+check ovn-sbctl set chassis ch1 other_config:ct-commit-nat-v2=false -+check ovn-nbctl --wait=sb sync -+ -+ovn-sbctl dump-flows lr0 > lr0flows -+AT_CHECK([grep -E "lr_out_post_snat.*ct_commit_nat" lr0flows], [1]) -+ - AT_CLEANUP - ]) - -@@ -6457,6 +6553,9 @@ AT_CAPTURE_FILE([lrflows]) - - # Check the flows in lr_in_admission stage - AT_CHECK([grep lr_in_admission lrflows | grep cr-DR | sort], [0], [dnl -+ table=0 (lr_in_admission ), priority=120 , match=(((ip4 && icmp4.type == 3 && icmp4.code == 4) || (ip6 && icmp6.type == 2 && icmp6.code == 0)) && eth.dst == 02:ac:10:01:00:01 && !is_chassis_resident("cr-DR-S1") && flags.tunnel_rx == 1), action=(outport <-> inport; inport = "DR-S1"; next;) -+ table=0 (lr_in_admission ), priority=120 , match=(((ip4 && icmp4.type == 3 && icmp4.code == 4) || (ip6 && icmp6.type == 2 && icmp6.code == 0)) && eth.dst == 03:ac:10:01:00:01 && !is_chassis_resident("cr-DR-S2") && flags.tunnel_rx == 1), action=(outport <-> inport; inport = "DR-S2"; next;) -+ table=0 (lr_in_admission ), priority=120 , match=(((ip4 && icmp4.type == 3 && icmp4.code == 4) || (ip6 && icmp6.type == 2 && icmp6.code == 0)) && eth.dst == 04:ac:10:01:00:01 && !is_chassis_resident("cr-DR-S3") && flags.tunnel_rx == 1), action=(outport <-> inport; inport = "DR-S3"; next;) - table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 02:ac:10:01:00:01 && inport == "DR-S1" && is_chassis_resident("cr-DR-S1")), action=(xreg0[[0..47]] = 02:ac:10:01:00:01; next;) - table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 03:ac:10:01:00:01 && inport == "DR-S2" && is_chassis_resident("cr-DR-S2")), action=(xreg0[[0..47]] = 03:ac:10:01:00:01; next;) - table=0 (lr_in_admission ), priority=50 , match=(eth.dst == 04:ac:10:01:00:01 && inport == "DR-S3" && is_chassis_resident("cr-DR-S3")), action=(xreg0[[0..47]] = 04:ac:10:01:00:01; next;) -@@ -6516,6 +6615,7 @@ AT_CAPTURE_FILE([lrflows]) - - # Check the flows in lr_in_admission stage - AT_CHECK([grep lr_in_admission lrflows | grep lrp1 | sed 's/table=../table=??/' | sort], [0], [dnl -+ table=??(lr_in_admission ), priority=120 , match=(((ip4 && icmp4.type == 3 && icmp4.code == 4) || (ip6 && icmp6.type == 2 && icmp6.code == 0)) && eth.dst == 00:00:00:00:00:01 && !is_chassis_resident("cr-lrp1") && flags.tunnel_rx == 1), action=(outport <-> inport; inport = "lrp1"; next;) - table=??(lr_in_admission ), priority=50 , match=(eth.dst == 00:00:00:00:00:01 && inport == "lrp1" && is_chassis_resident("cr-lrp1")), action=(xreg0[[0..47]] = 00:00:00:00:00:01; next;) - table=??(lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lrp1"), action=(xreg0[[0..47]] = 00:00:00:00:00:01; next;) - ]) -@@ -6537,6 +6637,7 @@ AT_CAPTURE_FILE([lrflows]) - - # Check the flows in lr_in_admission stage - AT_CHECK([grep lr_in_admission lrflows | grep lrp1 | sed 's/table=../table=??/' | sort], [0], [dnl -+ table=??(lr_in_admission ), priority=120 , match=(((ip4 && icmp4.type == 3 && icmp4.code == 4) || (ip6 && icmp6.type == 2 && icmp6.code == 0)) && eth.dst == 00:00:00:00:00:01 && !is_chassis_resident("cr-lrp1") && flags.tunnel_rx == 1), action=(outport <-> inport; inport = "lrp1"; next;) - table=??(lr_in_admission ), priority=50 , match=(eth.dst == 00:00:00:00:00:01 && inport == "lrp1"), action=(xreg0[[0..47]] = 00:00:00:00:00:01; next;) - table=??(lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lrp1"), action=(xreg0[[0..47]] = 00:00:00:00:00:01; next;) - ]) -@@ -6555,6 +6656,7 @@ AT_CAPTURE_FILE([lrflows]) - - # Check the flows in lr_in_admission stage - AT_CHECK([grep lr_in_admission lrflows | grep lrp1 | sed 's/table=../table=??/' | sort], [0], [dnl -+ table=??(lr_in_admission ), priority=120 , match=(((ip4 && icmp4.type == 3 && icmp4.code == 4) || (ip6 && icmp6.type == 2 && icmp6.code == 0)) && eth.dst == 00:00:00:00:00:01 && !is_chassis_resident("cr-lrp1") && flags.tunnel_rx == 1), action=(outport <-> inport; inport = "lrp1"; next;) - table=??(lr_in_admission ), priority=50 , match=(eth.dst == 00:00:00:00:00:01 && inport == "lrp1" && is_chassis_resident("cr-lrp1")), action=(xreg0[[0..47]] = 00:00:00:00:00:01; next;) - table=??(lr_in_admission ), priority=50 , match=(eth.mcast && inport == "lrp1"), action=(xreg0[[0..47]] = 00:00:00:00:00:01; next;) - ]) -@@ -7361,9 +7463,9 @@ AT_CHECK([grep lr_in_unsnat lrflows | grep ct_snat | sed 's/table=../table=??/' - ]) - - AT_CHECK([grep lr_out_snat lrflows | grep ct_snat | sed 's/table=../table=??/' | sort], [0], [dnl -- table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1")), action=(ct_snat(172.16.1.10);) -- table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S2" && is_chassis_resident("cr-DR-S2")), action=(ct_snat(10.0.0.10);) -- table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S3" && is_chassis_resident("cr-DR-S3")), action=(ct_snat(192.168.0.10);) -+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.10);) -+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S2" && is_chassis_resident("cr-DR-S2") && (!ct.trk || !ct.rpl)), action=(ct_snat(10.0.0.10);) -+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S3" && is_chassis_resident("cr-DR-S3") && (!ct.trk || !ct.rpl)), action=(ct_snat(192.168.0.10);) - ]) - - check ovn-nbctl --wait=sb lr-nat-del DR snat 20.0.0.10 -@@ -7437,9 +7539,9 @@ AT_CHECK([grep lr_in_unsnat lrflows | grep ct_snat | sed 's/table=../table=??/' - ]) - - AT_CHECK([grep lr_out_snat lrflows | grep ct_snat | sed 's/table=../table=??/' | sort], [0], [dnl -- table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1")), action=(ct_snat(172.16.1.10);) -- table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S2" && is_chassis_resident("cr-DR-S2")), action=(ct_snat(10.0.0.10);) -- table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S3" && is_chassis_resident("cr-DR-S3")), action=(ct_snat(192.168.0.10);) -+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S1" && is_chassis_resident("cr-DR-S1") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.10);) -+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S2" && is_chassis_resident("cr-DR-S2") && (!ct.trk || !ct.rpl)), action=(ct_snat(10.0.0.10);) -+ table=??(lr_out_snat ), priority=161 , match=(ip && ip4.src == 20.0.0.10 && outport == "DR-S3" && is_chassis_resident("cr-DR-S3") && (!ct.trk || !ct.rpl)), action=(ct_snat(192.168.0.10);) - ]) - - AT_CHECK([grep lr_in_dnat lrflows | grep ct_dnat | sed 's/table=../table=??/' | sort], [0], [dnl -@@ -8283,6 +8385,7 @@ AT_CHECK([cat sw0flows | grep -e port_sec -e ls_in_l2_lkup -e ls_in_l2_unknown | - sort | sed 's/table=../table=??/' ], [0], [dnl - table=??(ls_in_check_port_sec), priority=100 , match=(eth.src[[40]]), action=(drop;) - table=??(ls_in_check_port_sec), priority=100 , match=(vlan.present), action=(drop;) -+ table=??(ls_in_check_port_sec), priority=110 , match=(((ip4 && icmp4.type == 3 && icmp4.code == 4) || (ip6 && icmp6.type == 2 && icmp6.code == 0)) && flags.tunnel_rx == 1), action=(drop;) - table=??(ls_in_check_port_sec), priority=50 , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;) - table=??(ls_in_apply_port_sec), priority=0 , match=(1), action=(next;) - table=??(ls_in_apply_port_sec), priority=50 , match=(reg0[[15]] == 1), action=(drop;) -@@ -8308,6 +8411,7 @@ AT_CHECK([cat sw0flows | grep -e port_sec -e ls_in_l2_lkup -e ls_in_l2_unknown | - sort | sed 's/table=../table=??/' ], [0], [dnl - table=??(ls_in_check_port_sec), priority=100 , match=(eth.src[[40]]), action=(drop;) - table=??(ls_in_check_port_sec), priority=100 , match=(vlan.present), action=(drop;) -+ table=??(ls_in_check_port_sec), priority=110 , match=(((ip4 && icmp4.type == 3 && icmp4.code == 4) || (ip6 && icmp6.type == 2 && icmp6.code == 0)) && flags.tunnel_rx == 1), action=(drop;) - table=??(ls_in_check_port_sec), priority=50 , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;) - table=??(ls_in_apply_port_sec), priority=0 , match=(1), action=(next;) - table=??(ls_in_apply_port_sec), priority=50 , match=(reg0[[15]] == 1), action=(drop;) -@@ -8334,6 +8438,7 @@ AT_CHECK([cat sw0flows | grep -e port_sec -e ls_in_l2_lkup -e ls_in_l2_unknown | - sort | sed 's/table=../table=??/' ], [0], [dnl - table=??(ls_in_check_port_sec), priority=100 , match=(eth.src[[40]]), action=(drop;) - table=??(ls_in_check_port_sec), priority=100 , match=(vlan.present), action=(drop;) -+ table=??(ls_in_check_port_sec), priority=110 , match=(((ip4 && icmp4.type == 3 && icmp4.code == 4) || (ip6 && icmp6.type == 2 && icmp6.code == 0)) && flags.tunnel_rx == 1), action=(drop;) - table=??(ls_in_check_port_sec), priority=50 , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;) - table=??(ls_in_apply_port_sec), priority=0 , match=(1), action=(next;) - table=??(ls_in_apply_port_sec), priority=50 , match=(reg0[[15]] == 1), action=(drop;) -@@ -8361,6 +8466,7 @@ sort | sed 's/table=../table=??/' ], [0], [dnl - table=??(ls_in_check_port_sec), priority=100 , match=(eth.src[[40]]), action=(drop;) - table=??(ls_in_check_port_sec), priority=100 , match=(inport == "sw0p1"), action=(reg0[[15]] = 1; next;) - table=??(ls_in_check_port_sec), priority=100 , match=(vlan.present), action=(drop;) -+ table=??(ls_in_check_port_sec), priority=110 , match=(((ip4 && icmp4.type == 3 && icmp4.code == 4) || (ip6 && icmp6.type == 2 && icmp6.code == 0)) && flags.tunnel_rx == 1), action=(drop;) - table=??(ls_in_check_port_sec), priority=50 , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;) - table=??(ls_in_apply_port_sec), priority=0 , match=(1), action=(next;) - table=??(ls_in_apply_port_sec), priority=50 , match=(reg0[[15]] == 1), action=(drop;) -@@ -8387,6 +8493,7 @@ sort | sed 's/table=../table=??/' ], [0], [dnl - table=??(ls_in_check_port_sec), priority=100 , match=(eth.src[[40]]), action=(drop;) - table=??(ls_in_check_port_sec), priority=100 , match=(inport == "sw0p1"), action=(reg0[[15]] = 1; next;) - table=??(ls_in_check_port_sec), priority=100 , match=(vlan.present), action=(drop;) -+ table=??(ls_in_check_port_sec), priority=110 , match=(((ip4 && icmp4.type == 3 && icmp4.code == 4) || (ip6 && icmp6.type == 2 && icmp6.code == 0)) && flags.tunnel_rx == 1), action=(drop;) - table=??(ls_in_check_port_sec), priority=50 , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;) - table=??(ls_in_check_port_sec), priority=70 , match=(inport == "sw0p2"), action=(set_queue(10); reg0[[15]] = check_in_port_sec(); next;) - table=??(ls_in_apply_port_sec), priority=0 , match=(1), action=(next;) -@@ -8416,6 +8523,7 @@ AT_CHECK([cat sw0flows | grep -e port_sec -e ls_in_l2_lkup -e ls_in_l2_unknown | - sort | sed 's/table=../table=??/' ], [0], [dnl - table=??(ls_in_check_port_sec), priority=100 , match=(eth.src[[40]]), action=(drop;) - table=??(ls_in_check_port_sec), priority=100 , match=(vlan.present), action=(drop;) -+ table=??(ls_in_check_port_sec), priority=110 , match=(((ip4 && icmp4.type == 3 && icmp4.code == 4) || (ip6 && icmp6.type == 2 && icmp6.code == 0)) && flags.tunnel_rx == 1), action=(drop;) - table=??(ls_in_check_port_sec), priority=50 , match=(1), action=(reg0[[15]] = check_in_port_sec(); next;) - table=??(ls_in_check_port_sec), priority=70 , match=(inport == "localnetport"), action=(set_queue(10); reg0[[15]] = check_in_port_sec(); next;) - table=??(ls_in_check_port_sec), priority=70 , match=(inport == "sw0p1"), action=(reg0[[14]] = 1; next(pipeline=ingress, table=17);) -@@ -8618,7 +8726,7 @@ AT_CHECK([ovn-sbctl dump-flows ls0 | grep -e 'ls_in_\(put\|lookup\)_fdb' | sort - AT_CHECK([ovn-nbctl --wait=sb lsp-set-options ln_port localnet_learn_fdb=true]) - AT_CHECK([ovn-sbctl dump-flows ls0 | grep -e 'ls_in_\(put\|lookup\)_fdb' | sort | sed 's/table=./table=?/'], [0], [dnl - table=? (ls_in_lookup_fdb ), priority=0 , match=(1), action=(next;) -- table=? (ls_in_lookup_fdb ), priority=100 , match=(inport == "ln_port"), action=(reg0[[11]] = lookup_fdb(inport, eth.src); next;) -+ table=? (ls_in_lookup_fdb ), priority=100 , match=(inport == "ln_port"), action=(flags.localnet = 1; reg0[[11]] = lookup_fdb(inport, eth.src); next;) - table=? (ls_in_put_fdb ), priority=0 , match=(1), action=(next;) - table=? (ls_in_put_fdb ), priority=100 , match=(inport == "ln_port" && reg0[[11]] == 0), action=(put_fdb(inport, eth.src); next;) - ]) -@@ -8701,7 +8809,7 @@ AT_CHECK([grep "ls_in_lb " S1flows | sed 's/table=../table=??/' | sort], [0], [d - - ovn-sbctl get datapath S0 _uuid > dp_uuids - ovn-sbctl get datapath S1 _uuid >> dp_uuids --lb_dp_group=$(ovn-sbctl --bare --columns datapath_group find Load_Balancer name=lb0) -+lb_dp_group=$(ovn-sbctl --bare --columns ls_datapath_group find Load_Balancer name=lb0) - AT_CHECK_UNQUOTED([ovn-sbctl --bare --columns _uuid,datapaths find Logical_DP_Group dnl - | grep -A1 $lb_dp_group | tail -1 | tr ' ' '\n' | sort], [0], [dnl - $(cat dp_uuids | sort) -@@ -8827,8 +8935,8 @@ AT_CHECK([grep "ls_in_lb_aff_check" S0flows | sed 's/table=../table=??/' | sort] - AT_CHECK([grep "ls_in_lb " S0flows | sed 's/table=../table=??/' | sort], [0], [dnl - table=??(ls_in_lb ), priority=0 , match=(1), action=(next;) - table=??(ls_in_lb ), priority=120 , match=(ct.new && ip4.dst == 172.16.0.10 && tcp.dst == 80), action=(reg0[[1]] = 0; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);) -- table=??(ls_in_lb ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0[[1]] = 0; reg1 = 172.16.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.2:80);) -- table=??(ls_in_lb ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0[[1]] = 0; reg1 = 172.16.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=20.0.0.2:80);) -+ table=??(ls_in_lb ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0[[1]] = 0; reg1 = 172.16.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=10.0.0.2:80);) -+ table=??(ls_in_lb ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0[[1]] = 0; reg1 = 172.16.0.10; reg2[[0..15]] = 80; ct_lb_mark(backends=20.0.0.2:80);) - ]) - AT_CHECK([grep "ls_in_lb_aff_learn" S0flows | sed 's/table=../table=??/' | sort], [0], [dnl - table=??(ls_in_lb_aff_learn ), priority=0 , match=(1), action=(next;) -@@ -8847,8 +8955,8 @@ AT_CHECK([grep "lr_in_lb_aff_check" R1flows | sed 's/table=../table=??/' | sort] - AT_CHECK([grep "lr_in_dnat " R1flows | sed 's/table=../table=??/' | sort], [0], [dnl - table=??(lr_in_dnat ), priority=0 , match=(1), action=(next;) - table=??(lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80);) -- table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=10.0.0.2:80);) -- table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=20.0.0.2:80);) -+ table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=10.0.0.2:80);) -+ table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; ct_lb_mark(backends=20.0.0.2:80);) - table=??(lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) - table=??(lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) - table=??(lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) -@@ -8871,8 +8979,8 @@ AT_CAPTURE_FILE([R1flows_skip_snat]) - AT_CHECK([grep "lr_in_dnat " R1flows_skip_snat | sed 's/table=../table=??/' | sort], [0], [dnl - table=??(lr_in_dnat ), priority=0 , match=(1), action=(next;) - table=??(lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; skip_snat);) -- table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; skip_snat);) -- table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; skip_snat);) -+ table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; skip_snat);) -+ table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; skip_snat);) - table=??(lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) - table=??(lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) - table=??(lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) -@@ -8892,8 +9000,8 @@ AT_CAPTURE_FILE([R1flows_force_snat]) - AT_CHECK([grep "lr_in_dnat " R1flows_force_snat | sed 's/table=../table=??/' | sort], [0], [dnl - table=??(lr_in_dnat ), priority=0 , match=(1), action=(next;) - table=??(lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; force_snat);) -- table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; force_snat);) -- table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; force_snat);) -+ table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; force_snat);) -+ table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.force_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; force_snat);) - table=??(lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) - table=??(lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) - table=??(lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) -@@ -8912,8 +9020,35 @@ AT_CAPTURE_FILE([R1flows_force_skip_snat]) - AT_CHECK([grep "lr_in_dnat " R1flows_force_skip_snat | sed 's/table=../table=??/' | sort], [0], [dnl - table=??(lr_in_dnat ), priority=0 , match=(1), action=(next;) - table=??(lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; skip_snat);) -- table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; skip_snat);) -- table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; skip_snat);) -+ table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; skip_snat);) -+ table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; skip_snat);) -+ table=??(lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) -+ table=??(lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) -+ table=??(lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) -+ table=??(lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; next;) -+ table=??(lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; ct_commit_nat;) -+ table=??(lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) -+]) -+ -+AS_BOX([Test LR flows - 2 LBs, lb0 skip_snat=true, lb1 lb_force_snat_ip="172.16.0.1"]) -+check ovn-nbctl set logical_router R1 options:lb_force_snat_ip="172.16.0.1" -+check ovn-nbctl set load_balancer lb0 options:skip_snat=true -+check ovn-nbctl lb-add lb1 172.16.0.20:80 10.0.0.2:80,20.0.0.2:80 tcp -+check ovn-nbctl set load_balancer lb1 options:affinity_timeout=60 -+check ovn-nbctl lr-lb-add R1 lb1 -+check ovn-nbctl --wait=sb sync -+ -+ovn-sbctl dump-flows R1 > R1flows_2lbs -+AT_CAPTURE_FILE([R1flows_2lbs]) -+ -+AT_CHECK([grep "lr_in_dnat " R1flows_2lbs | sed 's/table=../table=??/' | sort], [0], [dnl -+ table=??(lr_in_dnat ), priority=0 , match=(1), action=(next;) -+ table=??(lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.10 && tcp && tcp.dst == 80), action=(flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; skip_snat);) -+ table=??(lr_in_dnat ), priority=120 , match=(ct.new && !ct.rel && ip4 && ip4.dst == 172.16.0.20 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80,20.0.0.2:80; force_snat);) -+ table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; skip_snat);) -+ table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.10 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.10; flags.skip_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; skip_snat);) -+ table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.20 && reg4 == 10.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.20; flags.force_snat_for_lb = 1; ct_lb_mark(backends=10.0.0.2:80; force_snat);) -+ table=??(lr_in_dnat ), priority=150 , match=(reg9[[6]] == 1 && ct.new && ip4.dst == 172.16.0.20 && reg4 == 20.0.0.2 && reg8[[0..15]] == 80), action=(reg0 = 172.16.0.20; flags.force_snat_for_lb = 1; ct_lb_mark(backends=20.0.0.2:80; force_snat);) - table=??(lr_in_dnat ), priority=50 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted), action=(next;) - table=??(lr_in_dnat ), priority=50 , match=(ct.rel && !ct.est && !ct.new), action=(ct_commit_nat;) - table=??(lr_in_dnat ), priority=70 , match=(ct.est && !ct.rel && !ct.new && ct_mark.natted && ct_mark.force_snat == 1), action=(flags.force_snat_for_lb = 1; next;) -@@ -8922,6 +9057,7 @@ AT_CHECK([grep "lr_in_dnat " R1flows_force_skip_snat | sed 's/table=../table=??/ - table=??(lr_in_dnat ), priority=70 , match=(ct.rel && !ct.est && !ct.new && ct_mark.skip_snat == 1), action=(flags.skip_snat_for_lb = 1; ct_commit_nat;) - ]) - -+ - AT_CLEANUP - ]) - -@@ -8985,7 +9121,6 @@ grep -c mutate], [0], [2 - # Pause ovn-northd and add/remove few addresses. when it is resumed - # it should use mutate for updating the address sets. - check as northd ovn-appctl -t NORTHD_TYPE pause --check as northd-backup ovn-appctl -t NORTHD_TYPE pause - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats - check ovn-nbctl add address_set $foo_as_uuid addresses 1.1.1.5 -@@ -10008,14 +10143,21 @@ ovs-vsctl add-br br-phys - ovn_attach n1 br-phys 192.168.0.11 - - check_recompute_counter() { -+ northd_recomp_min=$1 -+ northd_recomp_max=$2 -+ lflow_recomp_min=$3 -+ lflow_recomp_max=$4 -+ sync_sb_pb_recomp_min=$5 -+ sync_sb_pb_recomp_max=$6 -+ - northd_recomp=$(as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats northd recompute) -- AT_CHECK([test x$northd_recomp = x$1]) -+ AT_CHECK([test $northd_recomp -ge $northd_recomp_min && test $northd_recomp -le $northd_recomp_max]) - - lflow_recomp=$(as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats lflow recompute) -- AT_CHECK([test x$lflow_recomp = x$2]) -+ AT_CHECK([test $lflow_recomp -ge $lflow_recomp_min && test $lflow_recomp -le $lflow_recomp_max]) - - sync_sb_pb_recomp=$(as northd ovn-appctl -t NORTHD_TYPE inc-engine/show-stats sync_to_sb_pb recompute) -- AT_CHECK([test x$sync_sb_pb_recomp = x$3]) -+ AT_CHECK([test $sync_sb_pb_recomp -ge $sync_sb_pb_recomp_min && test $sync_sb_pb_recomp -le $sync_sb_pb_recomp_max]) - } - - check ovn-nbctl --wait=hv ls-add ls0 -@@ -10032,29 +10174,29 @@ check ovn-nbctl --wait=hv lsp-add ls0 lsp0-0 -- lsp-set-addresses lsp0-0 "unknow - ovs-vsctl add-port br-int lsp0-0 -- set interface lsp0-0 external_ids:iface-id=lsp0-0 - wait_for_ports_up - check ovn-nbctl --wait=hv sync --check_recompute_counter 5 5 5 -+check_recompute_counter 4 5 5 5 5 5 - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats - check ovn-nbctl --wait=hv lsp-add ls0 lsp0-1 -- lsp-set-addresses lsp0-1 "aa:aa:aa:00:00:01 192.168.0.11" - ovs-vsctl add-port br-int lsp0-1 -- set interface lsp0-1 external_ids:iface-id=lsp0-1 - wait_for_ports_up - check ovn-nbctl --wait=hv sync --check_recompute_counter 0 0 0 -+check_recompute_counter 0 0 0 0 0 0 - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats - check ovn-nbctl --wait=hv lsp-add ls0 lsp0-2 -- lsp-set-addresses lsp0-2 "aa:aa:aa:00:00:02 192.168.0.12" - ovs-vsctl add-port br-int lsp0-2 -- set interface lsp0-2 external_ids:iface-id=lsp0-2 - wait_for_ports_up - check ovn-nbctl --wait=hv sync --check_recompute_counter 0 0 0 -+check_recompute_counter 0 0 0 0 0 0 - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats - check ovn-nbctl --wait=hv lsp-del lsp0-1 --check_recompute_counter 0 0 0 -+check_recompute_counter 0 0 0 0 0 0 - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats - check ovn-nbctl --wait=hv lsp-set-addresses lsp0-2 "aa:aa:aa:00:00:88 192.168.0.88" --check_recompute_counter 0 0 0 -+check_recompute_counter 0 0 0 0 0 0 - - # Delete and re-add a LSP for several times continuously, to ensure - # frequent operations do not trigger recompute when there are in-flight -@@ -10068,14 +10210,14 @@ for i in $(seq 10); do - check ovn-nbctl lsp-del lsp0-2 - check ovn-nbctl lsp-add ls0 lsp0-2 -- lsp-set-addresses lsp0-2 "aa:aa:aa:00:00:02 192.168.0.12" - done --check_recompute_counter 0 0 0 -+check_recompute_counter 0 0 0 0 0 0 - - # No change, no recompute - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats - check ovn-nbctl --wait=sb sync --check_recompute_counter 0 0 0 -+check_recompute_counter 0 0 0 0 0 0 - --CHECK_NO_CHANGE_AFTER_RECOMPUTE -+CHECK_NO_CHANGE_AFTER_RECOMPUTE(1) - - # Associate DHCP for lsp0-2 - ovn-nbctl dhcp-options-create 192.168.0.0/24 -@@ -10085,9 +10227,9 @@ ovn-nbctl dhcp-options-set-options $CIDR_UUID lease_time=3600 router=192.168. - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats - ovn-nbctl --wait=sb lsp-set-dhcpv4-options lsp0-2 $CIDR_UUID --check_recompute_counter 0 0 0 -+check_recompute_counter 0 0 0 0 0 0 - --CHECK_NO_CHANGE_AFTER_RECOMPUTE -+CHECK_NO_CHANGE_AFTER_RECOMPUTE(1) - - # Add IPv6 address and associate DHCPv6 for lsp0-2 - check ovn-nbctl lsp-set-addresses lsp0-2 "aa:aa:aa:00:00:01 192.168.0.11 aef0::4" -@@ -10096,9 +10238,9 @@ options="\"server_id\"=\"00:00:00:10:00:01\"")" - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats - ovn-nbctl --wait=sb lsp-set-dhcpv6-options lsp0-2 ${d1} --check_recompute_counter 0 0 0 -+check_recompute_counter 0 0 0 0 0 0 - --CHECK_NO_CHANGE_AFTER_RECOMPUTE -+CHECK_NO_CHANGE_AFTER_RECOMPUTE(1) - - check ovn-nbctl --wait=hv ls-del ls0 - -@@ -10125,11 +10267,11 @@ ovn-nbctl lsp-add ls0 ls0-lr0 - ovn-nbctl lsp-set-type ls0-lr0 router - ovn-nbctl lsp-set-addresses ls0-lr0 router - check ovn-nbctl --wait=sb lsp-set-options ls0-lr0 router-port=lr0-ls0 --CHECK_NO_CHANGE_AFTER_RECOMPUTE -+CHECK_NO_CHANGE_AFTER_RECOMPUTE(1) - - ovn-nbctl lb-add lb0 192.168.0.10:80 10.0.0.10:8080 - check ovn-nbctl --wait=sb ls-lb-add ls0 lb0 --CHECK_NO_CHANGE_AFTER_RECOMPUTE -+CHECK_NO_CHANGE_AFTER_RECOMPUTE(1) - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats - # Add a lsp. northd and lflow engine shouldn't recompute even though this is -@@ -10216,14 +10358,14 @@ check ovn-nbctl --wait=sb meter-add m drop 1 pktps - check ovn-nbctl --wait=sb acl-add ls from-lport 1 1 allow - dnl Only triggers recompute of the sync_meters and lflow nodes. - check_recompute_counter 0 2 2 --CHECK_NO_CHANGE_AFTER_RECOMPUTE -+CHECK_NO_CHANGE_AFTER_RECOMPUTE(1) - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats - check ovn-nbctl --wait=sb meter-del m - check ovn-nbctl --wait=sb acl-del ls - dnl Only triggers recompute of the sync_meters and lflow nodes. - check_recompute_counter 0 2 2 --CHECK_NO_CHANGE_AFTER_RECOMPUTE -+CHECK_NO_CHANGE_AFTER_RECOMPUTE(1) - - AT_CLEANUP - ]) -@@ -10339,7 +10481,7 @@ wait_for_ports_up sw0-r1 - check_column $remote_chassis_uuid Port_Binding chassis logical_port=sw0-r1 - - # Set the type to router and ovn-northd should not claim it. --check ovn-nbctl lsp-set-type sw0-r1 router -+check ovn-nbctl --wait=hv lsp-set-type sw0-r1 router - check_column '' Port_Binding chassis logical_port=sw0-r1 - - AT_CLEANUP -@@ -10391,34 +10533,39 @@ check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - --CHECK_NO_CHANGE_AFTER_RECOMPUTE -+CHECK_NO_CHANGE_AFTER_RECOMPUTE(1) - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats - - check ovn-nbctl --wait=sb set load_balancer . ip_port_mappings:10.0.0.3=sw0-p1:10.0.0.2 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - - check ovn-nbctl --wait=sb set load_balancer . options:foo=bar - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - - check ovn-nbctl --wait=sb -- lb-add lb2 20.0.0.10:80 20.0.0.20:80 -- lb-add lb3 30.0.0.10:80 30.0.0.20:80 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - --CHECK_NO_CHANGE_AFTER_RECOMPUTE -+CHECK_NO_CHANGE_AFTER_RECOMPUTE(1) - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats - - check ovn-nbctl --wait=sb -- lb-del lb2 -- lb-del lb3 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - --CHECK_NO_CHANGE_AFTER_RECOMPUTE -+CHECK_NO_CHANGE_AFTER_RECOMPUTE(1) - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats - - AT_CHECK([ovn-nbctl --wait=sb \ -@@ -10429,6 +10576,7 @@ AT_CHECK([ovn-nbctl --wait=sb \ - check_engine_stats lb_data norecompute compute - check_engine_stats northd recompute nocompute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - - # Any change to load balancer health check should also result in full recompute - # of northd node (but not northd_lb_data node) -@@ -10437,6 +10585,7 @@ check ovn-nbctl --wait=sb set load_balancer_health_check . options:foo=bar1 - check_engine_stats lb_data norecompute compute - check_engine_stats northd recompute nocompute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - - # Delete the health check from the load balancer. northd engine node should do a full recompute. - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10444,6 +10593,7 @@ check ovn-nbctl --wait=sb clear Load_Balancer . health_check - check_engine_stats lb_data norecompute compute - check_engine_stats northd recompute nocompute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats - check ovn-nbctl ls-add sw0 -@@ -10457,6 +10607,7 @@ ovn-nbctl --wait=sb lsp-set-options sw0-lr0 router-port=lr0-sw0 - check_engine_stats lb_data norecompute compute - check_engine_stats northd recompute nocompute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - - # Associate lb1 to sw0. There should be no recompute of northd engine node - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10464,7 +10615,11 @@ check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute --CHECK_NO_CHANGE_AFTER_RECOMPUTE -+# A LB applied to a switch/router triggers: -+# - a recompute in the first iteration (handling northd change) -+# - a compute in the second iteration (handling SB update) -+check_engine_stats sync_to_sb_lb recompute compute -+CHECK_NO_CHANGE_AFTER_RECOMPUTE(1) - - # Modify the backend of the lb1 vip - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10472,7 +10627,8 @@ check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.1 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute --CHECK_NO_CHANGE_AFTER_RECOMPUTE -+check_engine_stats sync_to_sb_lb recompute compute -+CHECK_NO_CHANGE_AFTER_RECOMPUTE(1) - - # Cleanup the vip of lb1. - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10480,7 +10636,8 @@ check ovn-nbctl --wait=sb clear load_Balancer lb1 vips - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute --CHECK_NO_CHANGE_AFTER_RECOMPUTE -+check_engine_stats sync_to_sb_lb recompute compute -+CHECK_NO_CHANGE_AFTER_RECOMPUTE(1) - - # Set the vips of lb1 back - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10488,7 +10645,8 @@ check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute --CHECK_NO_CHANGE_AFTER_RECOMPUTE -+check_engine_stats sync_to_sb_lb recompute compute -+CHECK_NO_CHANGE_AFTER_RECOMPUTE(1) - - # Add another vip to lb1 - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10496,7 +10654,8 @@ check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute --CHECK_NO_CHANGE_AFTER_RECOMPUTE -+check_engine_stats sync_to_sb_lb recompute compute -+CHECK_NO_CHANGE_AFTER_RECOMPUTE(1) - - # Disassociate lb1 from sw0. There should be a full recompute of northd engine node. - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10504,7 +10663,8 @@ check ovn-nbctl --wait=sb ls-lb-del sw0 lb1 - check_engine_stats lb_data norecompute compute - check_engine_stats northd recompute nocompute - check_engine_stats lflow recompute nocompute --CHECK_NO_CHANGE_AFTER_RECOMPUTE -+check_engine_stats sync_to_sb_lb recompute compute -+CHECK_NO_CHANGE_AFTER_RECOMPUTE(1) - - # Associate lb1 to sw0 and also create a port sw0p1. This should not result in - # full recompute of northd, but should rsult in full recompute of lflow node. -@@ -10513,6 +10673,7 @@ check ovn-nbctl --wait=sb ls-lb-add sw0 lb1 -- lsp-add sw0 sw0p1 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - - CHECK_NO_CHANGE_AFTER_RECOMPUTE - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10523,6 +10684,7 @@ check ovn-nbctl --wait=sb ls-lb-del sw0 lb1 - check_engine_stats lb_data norecompute compute - check_engine_stats northd recompute nocompute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - # Add lb1 to lr0 and then disassociate -@@ -10531,6 +10693,7 @@ check ovn-nbctl --wait=sb lr-lb-add lr0 lb1 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - # Modify the backend of the lb1 vip -@@ -10539,6 +10702,7 @@ check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.1 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - # Cleanup the vip of lb1. -@@ -10547,6 +10711,7 @@ check ovn-nbctl --wait=sb clear load_Balancer lb1 vips - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - # Set the vips of lb1 back -@@ -10555,6 +10720,7 @@ check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - # Add another vip to lb1 -@@ -10563,6 +10729,7 @@ check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10570,14 +10737,16 @@ check ovn-nbctl --wait=sb lr-lb-del lr0 lb1 - check_engine_stats lb_data norecompute compute - check_engine_stats northd recompute nocompute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - # Test load balancer group now - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats --lbg1_uuid=$(ovn-nbctl create load_balancer_group name=lbg1) -+lbg1_uuid=$(ovn-nbctl --wait=sb create load_balancer_group name=lbg1) - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - - CHECK_NO_CHANGE_AFTER_RECOMPUTE - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10586,31 +10755,35 @@ lb1_uuid=$(fetch_column nb:Load_Balancer _uuid) - - # Add lb to the lbg1 group - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats --check ovn-nbctl add load_balancer_group . load_Balancer $lb1_uuid -+check ovn-nbctl --wait=sb add load_balancer_group . load_Balancer $lb1_uuid - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats --check ovn-nbctl clear load_balancer_group . load_Balancer -+check ovn-nbctl --wait=sb clear load_balancer_group . load_Balancer - check_engine_stats lb_data norecompute compute - check_engine_stats northd recompute nocompute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - - # Add back lb to the lbg1 group - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats --check ovn-nbctl add load_balancer_group . load_Balancer $lb1_uuid -+check ovn-nbctl --wait=sb add load_balancer_group . load_Balancer $lb1_uuid - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats --check ovn-nbctl add logical_switch sw0 load_balancer_group $lbg1_uuid -+check ovn-nbctl --wait=sb add logical_switch sw0 load_balancer_group $lbg1_uuid - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - - # Update lb and this should not result in northd recompute - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10618,6 +10791,7 @@ check ovn-nbctl --wait=sb set load_balancer . options:bar=foo - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - - # Modify the backend of the lb1 vip - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10625,6 +10799,7 @@ check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.1 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - # Cleanup the vip of lb1. -@@ -10633,6 +10808,7 @@ check ovn-nbctl --wait=sb clear load_Balancer lb1 vips - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - # Set the vips of lb1 back -@@ -10641,6 +10817,7 @@ check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - # Add another vip to lb1 -@@ -10649,19 +10826,22 @@ check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats --check ovn-nbctl clear logical_switch sw0 load_balancer_group -+check ovn-nbctl --wait=sb clear logical_switch sw0 load_balancer_group - check_engine_stats lb_data norecompute compute - check_engine_stats northd recompute nocompute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats - check ovn-nbctl add logical_router lr0 load_balancer_group $lbg1_uuid - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - # Modify the backend of the lb1 vip -@@ -10670,6 +10850,7 @@ check ovn-nbctl --wait=sb set load_balancer lb1 vips:'"10.0.0.10:80"'='"10.0.0.1 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - # Cleanup the vip of lb1. -@@ -10678,6 +10859,7 @@ check ovn-nbctl --wait=sb clear load_Balancer lb1 vips - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - # Set the vips of lb1 back -@@ -10686,6 +10868,7 @@ check ovn-nbctl --wait=sb lb-add lb1 10.0.0.10:80 10.0.0.3:80 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - # Add another vip to lb1 -@@ -10694,27 +10877,31 @@ check ovn-nbctl --wait=sb lb-add lb1 10.0.0.20:80 10.0.0.30:8080 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats --check ovn-nbctl clear logical_router lr0 load_balancer_group -+check ovn-nbctl --wait=sb clear logical_router lr0 load_balancer_group - check_engine_stats lb_data norecompute compute - check_engine_stats northd recompute nocompute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - - # Add back lb group to logical switch and then delete it. - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats --check ovn-nbctl add logical_switch sw0 load_balancer_group $lbg1_uuid -+check ovn-nbctl --wait=sb add logical_switch sw0 load_balancer_group $lbg1_uuid - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats --check ovn-nbctl clear logical_switch sw0 load_balancer_group -- \ -+check ovn-nbctl --wait=sb clear logical_switch sw0 load_balancer_group -- \ - destroy load_balancer_group $lbg1_uuid - check_engine_stats lb_data norecompute compute - check_engine_stats northd recompute nocompute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb compute compute - - CHECK_NO_CHANGE_AFTER_RECOMPUTE - -@@ -10733,29 +10920,33 @@ lb3_uuid=$(fetch_column nb:Load_Balancer _uuid name=lb3) - lb4_uuid=$(fetch_column nb:Load_Balancer _uuid name=lb4) - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats --lbg1_uuid=$(ovn-nbctl create load_balancer_group name=lbg1) -+lbg1_uuid=$(ovn-nbctl --wait=sb create load_balancer_group name=lbg1) - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats --check ovn-nbctl set load_balancer_group . load_balancer="$lb2_uuid,$lb3_uuid,$lb4_uuid" -+check ovn-nbctl --wait=sb set load_balancer_group . load_balancer="$lb2_uuid,$lb3_uuid,$lb4_uuid" - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats --check ovn-nbctl set logical_switch sw0 load_balancer_group=$lbg1_uuid -+check ovn-nbctl --wait=sb set logical_switch sw0 load_balancer_group=$lbg1_uuid - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats --check ovn-nbctl set logical_router lr1 load_balancer_group=$lbg1_uuid -+check ovn-nbctl --wait=sb set logical_router lr1 load_balancer_group=$lbg1_uuid - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10763,6 +10954,7 @@ check ovn-nbctl --wait=sb ls-lb-add sw0 lb2 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10770,6 +10962,7 @@ check ovn-nbctl --wait=sb ls-lb-add sw0 lb3 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10778,6 +10971,7 @@ check ovn-nbctl --wait=sb lr-lb-add lr1 lb2 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10785,6 +10979,7 @@ check ovn-nbctl --wait=sb ls-lb-del sw0 lb2 - check_engine_stats lb_data norecompute compute - check_engine_stats northd recompute nocompute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10792,6 +10987,7 @@ check ovn-nbctl --wait=sb lr-lb-del lr1 lb2 - check_engine_stats lb_data norecompute compute - check_engine_stats northd recompute nocompute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute nocompute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - # Deleting lb4 should not result in lflow recompute as it is -@@ -10801,6 +10997,7 @@ check ovn-nbctl --wait=sb lb-del lb4 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - # Deleting lb2 should result in lflow recompute as it is -@@ -10810,6 +11007,7 @@ check ovn-nbctl --wait=sb lb-del lb2 - check_engine_stats lb_data norecompute compute - check_engine_stats northd norecompute compute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - check as northd ovn-appctl -t NORTHD_TYPE inc-engine/clear-stats -@@ -10817,7 +11015,61 @@ check ovn-nbctl --wait=sb remove load_balancer_group . load_balancer $lb3_uuid - check_engine_stats lb_data norecompute compute - check_engine_stats northd recompute nocompute - check_engine_stats lflow recompute nocompute -+check_engine_stats sync_to_sb_lb recompute compute - CHECK_NO_CHANGE_AFTER_RECOMPUTE - - AT_CLEANUP - ]) -+ -+OVN_FOR_EACH_NORTHD_NO_HV([ -+AT_SETUP([Load balancer incremental processing - batched updates]) -+ovn_start -+ -+# Check the scenario when a LB is created and quickly deleted (northd -+# processes this in a single iteration). -+ -+check ovn-nbctl ls-add sw0 -+lbg_uuid=$(ovn-nbctl --wait=sb create load_balancer_group name=lbg) -+check ovn-nbctl --wait=sb add logical_switch sw0 load_balancer_group $lbg_uuid -+ -+# Pause ovn-northd. -+sleep_northd -+ -+check ovn-nbctl lb-add lb-temp 50.0.0.10:80 50.0.0.20:8080 -+lb_temp_uuid=$(fetch_column nb:Load_Balancer _uuid name=lb-temp) -+check ovn-nbctl add load_balancer_group $lbg_uuid load_balancer $lb_temp_uuid -+check ovn-nbctl lb-del lb-temp -+ -+# Let ovn-northd process all the updates that happened since it went to sleep. -+wake_up_northd -+ -+# Add a new load balancer to make sure northd still functions properly. -+check ovn-nbctl lb-add lb1 50.0.0.10:80 50.0.0.30:8080 -+lb1_uuid=$(fetch_column nb:Load_Balancer _uuid name=lb1) -+check ovn-nbctl add load_balancer_group $lbg_uuid load_balancer $lb1_uuid -+ -+check ovn-nbctl --wait=sb sync -+CHECK_NO_CHANGE_AFTER_RECOMPUTE -+ -+# Re-check the same scenario but now also batch the additional LB creation. -+sleep_northd -+check ovn-nbctl lb-add lb-temp 50.0.0.10:80 50.0.0.20:8080 -+lb_temp_uuid=$(fetch_column nb:Load_Balancer _uuid name=lb-temp) -+check ovn-nbctl add load_balancer_group $lbg_uuid load_balancer $lb_temp_uuid -+check ovn-nbctl lb-del lb-temp -+ -+# Add a new load balancer to make sure northd still functions properly. -+check ovn-nbctl lb-add lb2 50.0.0.10:80 50.0.0.30:8080 -+lb2_uuid=$(fetch_column nb:Load_Balancer _uuid name=lb2) -+check ovn-nbctl add load_balancer_group $lbg_uuid load_balancer $lb2_uuid -+ -+wake_up_northd -+check ovn-nbctl --wait=sb sync -+CHECK_NO_CHANGE_AFTER_RECOMPUTE -+ -+AT_CHECK([as northd ovn-appctl -t NORTHD_TYPE status], [0], [dnl -+Status: active -+]) -+ -+AT_CLEANUP -+]) -diff --git a/tests/ovn.at b/tests/ovn.at -index e127530f6..07cc0e515 100644 ---- a/tests/ovn.at -+++ b/tests/ovn.at -@@ -23,8 +23,11 @@ m4_divert_text([PREPARE_TESTS], - diff -u $exp_text.sorted $rcv_text.sorted - } - ovn_check_packets__ () { -- echo -- echo "$3: checking packets in $1 against $2:" -+ if [[ -n "$4" ]]; then -+ echo "$3: checking packets in $1 against $2: using $4" -+ else -+ echo "$3: checking packets in $1 against $2:" -+ fi - rcv_pcap=$1 - rcv_text=`echo "$rcv_pcap.packets" | sed 's/\.pcap//'` - exp_text=$2 -@@ -35,7 +38,13 @@ m4_divert_text([PREPARE_TESTS], - echo "rcv_n=$rcv_n exp_n=$exp_n" - test $rcv_n -ge $exp_n], - [dump_diff__ "$rcv_pcap" "$exp_text"]) -- sort $exp_text > expout -+ if [[ -n "$4" ]]; then -+ sort $exp_text | $4 > expout -+ cat $rcv_text | $4 > rcv_tmp -+ mv rcv_tmp $rcv_text -+ else -+ sort $exp_text > expout -+ fi - } - ovn_check_packets_remove_broadcast__ () { - echo "$3: checking packets in $1 against $2:" -@@ -54,14 +63,26 @@ m4_divert_text([PREPARE_TESTS], - } - ovn_wait_packets__ () { - echo "$3: waiting for packets from $2 at $1:" -+ if [[ -n "$4" ]]; then -+ echo "$3: checking packets from $2 at $1: using $4" -+ else -+ echo "$3: checking packets from $2 at $1:" -+ fi - rcv_pcap=$1 - rcv_text=`echo "$rcv_pcap.packets" | sed 's/\.pcap//'` - exp_text=$2 -+ if [[ -n "$4" ]]; then -+ cmd=$4 -+ else -+ cmd=cat -+ fi - OVS_WAIT_UNTIL( - [$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" $rcv_pcap > $rcv_text -- sort $exp_text > expout -- test x"$(sort $rcv_text | comm -2 -3 expout -)" = "x"], -+ sort $exp_text | $cmd > expout -+ test x"$(sort $rcv_text | $cmd | comm -2 -3 expout -)" = "x"], - [dump_diff__ "$rcv_pcap" "$exp_text"]) -+ cat $rcv_text | $cmd > rcv_tmp -+ mv rcv_tmp $rcv_text - } - ovn_wait_packets_uniq__ () { - echo "$3: waiting for packets from $2 at $1:" -@@ -140,7 +161,7 @@ m4_divert_text([PREPARE_TESTS], - - m4_define([OVN_CHECK_PACKETS], - [AT_CHECK([$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" $1 ], [0], [ignore]) -- ovn_check_packets__ "$1" "$2" "__file__:__line__" -+ ovn_check_packets__ "$1" "$2" "__file__:__line__" $3 - AT_CHECK([sort $rcv_text], [0], [expout], [ignore], [dump_diff__ "$1" "$2"])]) - - m4_define([OVN_CHECK_PACKETS_REMOVE_BROADCAST], -@@ -148,7 +169,7 @@ m4_define([OVN_CHECK_PACKETS_REMOVE_BROADCAST], - AT_CHECK([sort $rcv_text], [0], [expout], [ignore], [dump_diff__ "$1" "$2"])]) - - m4_define([OVN_CHECK_PACKETS_CONTAIN], -- [ovn_wait_packets__ "$1" "$2" "__file__:__line__"]) -+ [ovn_wait_packets__ "$1" "$2" "__file__:__line__" $3]) - - # OVN_CHECK_PACKETS_UNIQ succeeds if some expected packets are duplicated. - # It fails if unexpected packets are received. -@@ -1347,7 +1368,7 @@ ct_dnat(fd11::2); - has prereqs ip - ct_dnat(192.168.1.2, 1-3000); - formats as ct_dnat(192.168.1.2,1-3000); -- encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=192.168.1.2:1-3000)) -+ encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=192.168.1.2:1-3000,random)) - has prereqs ip - - ct_dnat(192.168.1.2, 192.168.1.3); -@@ -1381,7 +1402,7 @@ ct_dnat_in_czone(fd11::2); - has prereqs ip - ct_dnat_in_czone(192.168.1.2, 1-3000); - formats as ct_dnat_in_czone(192.168.1.2,1-3000); -- encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=192.168.1.2:1-3000)) -+ encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=192.168.1.2:1-3000,random)) - has prereqs ip - - ct_dnat_in_czone(192.168.1.2, 192.168.1.3); -@@ -1415,7 +1436,7 @@ ct_snat(fd11::2); - has prereqs ip - ct_snat(192.168.1.2, 1-3000); - formats as ct_snat(192.168.1.2,1-3000); -- encodes as ct(commit,table=19,zone=NXM_NX_REG12[0..15],nat(src=192.168.1.2:1-3000)) -+ encodes as ct(commit,table=19,zone=NXM_NX_REG12[0..15],nat(src=192.168.1.2:1-3000,random)) - has prereqs ip - - ct_snat(192.168.1.2, 192.168.1.3); -@@ -1449,7 +1470,7 @@ ct_snat_in_czone(fd11::2); - has prereqs ip - ct_snat_in_czone(192.168.1.2, 1-3000); - formats as ct_snat_in_czone(192.168.1.2,1-3000); -- encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(src=192.168.1.2:1-3000)) -+ encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(src=192.168.1.2:1-3000,random)) - has prereqs ip - - ct_snat_in_czone(192.168.1.2, 192.168.1.3); -@@ -1477,9 +1498,30 @@ ct_clear; - - # ct_commit_nat - ct_commit_nat; -+ formats as ct_commit_nat(dnat); -+ encodes as ct(commit,table=19,zone=NXM_NX_REG13[0..15],nat) -+ has prereqs ip -+ -+ct_commit_nat(snat); -+ encodes as ct(commit,table=19,zone=NXM_NX_REG13[0..15],nat) -+ has prereqs ip -+ -+ct_commit_nat(dnat); - encodes as ct(commit,table=19,zone=NXM_NX_REG13[0..15],nat) - has prereqs ip - -+ct_commit_nat(snat, dnat); -+ Syntax error at `,' expecting `)'. -+ -+ct_commit_nat(dnat, ignore); -+ Syntax error at `,' expecting `)'. -+ -+ct_commit_nat(ignore); -+ "ct_commit_nat" action accepts only "dnat" or "snat" parameter. -+ -+ct_commit_nat(); -+ "ct_commit_nat" action accepts only "dnat" or "snat" parameter. -+ - # clone - clone { ip4.dst = 255.255.255.255; output; }; next; - encodes as clone(set_field:255.255.255.255->ip_dst,resubmit(,64)),resubmit(,19) -@@ -2198,13 +2240,13 @@ reg9[5] = chk_ecmp_nh(); - - # commit_lb_aff - commit_lb_aff(vip = "172.16.0.123:8080", backend = "10.0.0.3:8080", proto = tcp, timeout = 30); -- encodes as learn(table=78,idle_timeout=30,delete_learned,OXM_OF_METADATA[],eth_type=0x800,NXM_OF_IP_SRC[],ip_dst=172.16.0.123,nw_proto=6,tcp_dst=8080,load:0x1->NXM_NX_REG10[14],load:0xa000003->NXM_NX_REG4[],load:0x1f90->NXM_NX_REG8[0..15]) -+ encodes as learn(table=78,idle_timeout=30,delete_learned,cookie=0xaaaaaaaa,OXM_OF_METADATA[],eth_type=0x800,NXM_OF_IP_SRC[],ip_dst=172.16.0.123,nw_proto=6,tcp_dst=8080,load:0x1->NXM_NX_REG10[14],load:0xa000003->NXM_NX_REG4[],load:0x1f90->NXM_NX_REG8[0..15]) - - commit_lb_aff(vip = "172.16.0.123", backend = "10.0.0.3", timeout = 30); -- encodes as learn(table=78,idle_timeout=30,delete_learned,OXM_OF_METADATA[],eth_type=0x800,NXM_OF_IP_SRC[],ip_dst=172.16.0.123,load:0x1->NXM_NX_REG10[14],load:0xa000003->NXM_NX_REG4[]) -+ encodes as learn(table=78,idle_timeout=30,delete_learned,cookie=0xaaaaaaaa,OXM_OF_METADATA[],eth_type=0x800,NXM_OF_IP_SRC[],ip_dst=172.16.0.123,load:0x1->NXM_NX_REG10[14],load:0xa000003->NXM_NX_REG4[]) - - commit_lb_aff(vip = "[::1]:8080", backend = "[::2]:8080", proto = tcp, timeout = 30); -- encodes as learn(table=78,idle_timeout=30,delete_learned,OXM_OF_METADATA[],eth_type=0x86dd,NXM_NX_IPV6_SRC[],ipv6_dst=::1,nw_proto=6,tcp_dst=8080,load:0x1->NXM_NX_REG10[14],load:0x2->NXM_NX_XXREG0[],load:0x1f90->NXM_NX_REG8[0..15]) -+ encodes as learn(table=78,idle_timeout=30,delete_learned,cookie=0xaaaaaaaa,OXM_OF_METADATA[],eth_type=0x86dd,NXM_NX_IPV6_SRC[],ipv6_dst=::1,nw_proto=6,tcp_dst=8080,load:0x1->NXM_NX_REG10[14],load:0x2->NXM_NX_XXREG0[],load:0x1f90->NXM_NX_REG8[0..15]) - - # chk_lb_aff() - reg9[6] = chk_lb_aff(); -@@ -3849,7 +3891,7 @@ OVN_FOR_EACH_NORTHD([ - AT_SETUP([VLAN transparency, passthru=true, multiple hosts, custom ethtype]) - ovn_start - --ethtype=802.11ad -+ethtype=802.1ad - - check ovn-nbctl ls-add ls - check ovn-nbctl --wait=sb add Logical-Switch ls other_config vlan-passthru=true -@@ -4650,6 +4692,12 @@ OVN_POPULATE_ARP - - wait_for_ports_up - check ovn-nbctl --wait=hv sync -+OVN_WAIT_REMOTE_OUTPUT_FLOWS(["hv1"],["hv2"]) -+OVN_WAIT_REMOTE_OUTPUT_FLOWS(["hv2"],["hv1"]) -+OVN_WAIT_REMOTE_OUTPUT_FLOWS(["hv1"],["hv_gw"]) -+OVN_WAIT_REMOTE_OUTPUT_FLOWS(["hv_gw"],["hv1"]) -+OVN_WAIT_REMOTE_OUTPUT_FLOWS(["hv2"],["hv_gw"]) -+OVN_WAIT_REMOTE_OUTPUT_FLOWS(["hv_gw"],["hv2"]) - - # test_packet INPORT DST SRC ETHTYPE OUTPORT... - # -@@ -4849,6 +4897,13 @@ check ovn-nbctl --wait=hv sync - # for ARP resolution). - OVN_POPULATE_ARP - -+OVN_WAIT_REMOTE_OUTPUT_FLOWS(["hv1"],["hv2"]) -+OVN_WAIT_REMOTE_OUTPUT_FLOWS(["hv2"],["hv1"]) -+OVN_WAIT_REMOTE_OUTPUT_FLOWS(["hv2"],["hv3"]) -+OVN_WAIT_REMOTE_OUTPUT_FLOWS(["hv3"],["hv2"]) -+OVN_WAIT_REMOTE_OUTPUT_FLOWS(["hv1"],["hv3"]) -+OVN_WAIT_REMOTE_OUTPUT_FLOWS(["hv3"],["hv1"]) -+ - # test_ip INPORT SRC_MAC DST_MAC SRC_IP DST_IP OUTPORT... - # - # This shell function causes a packet to be received on INPORT. The packet's -@@ -5320,10 +5375,11 @@ test_arp() { - } - - test_na() { -- local inport=$1 sha=$2 spa=$3 -+ local inport=$1 sha=$2 spa=$3 src=${4-$3} - local request=$(fmt_pkt "Ether(dst='ff:ff:ff:ff:ff:ff', src='${sha}')/ \ -- IPv6(dst='ff01::1', src='${spa}')/ \ -- ICMPv6ND_NA(tgt='${spa}')") -+ IPv6(dst='ff01::1', src='${src}')/ \ -+ ICMPv6ND_NA(tgt='${spa}')/ \ -+ ICMPv6NDOptDstLLAddr(lladdr='${sha}')") - - hv=hv`vif_to_hv $inport` - as $hv ovs-appctl netdev-dummy/receive vif$inport $request -@@ -5399,6 +5455,24 @@ for i in 1 2; do - done - done - -+# Make sure that we can update existing entry with -+# "always_learn_from_arp_request=false" even when the source of NA src is LLA. -+check ovn-sbctl --all destroy mac_binding -+check ovn-nbctl --wait=hv set logical_router lr0 options:always_learn_from_arp_request=false -+ -+sha="f0:00:00:00:00:11" -+spa6="fd00::abcd:1" -+ -+test_na 11 $sha $spa6 -+wait_row_count MAC_Binding 1 ip=\"$spa6\" mac=\"$sha\" -+ -+sha="f0:00:00:00:00:12" -+lla6="fe80::abcd:1" -+ -+test_na 11 $sha $spa6 $lla6 -+wait_row_count MAC_Binding 1 ip=\"$spa6\" mac=\"$sha\" -+check_row_count MAC_Binding 0 ip=\"$lla6\" -+ - # Gracefully terminate daemons - OVN_CLEANUP([hv1], [hv2]) - -@@ -6107,7 +6181,7 @@ ovs-vsctl -- add-port br-int vif2 -- \ - wait_for_ports_up - check ovn-nbctl --wait=hv sync - --ovs-sbctl dump-flows > sbflows -+ovn-sbctl dump-flows > sbflows - AT_CAPTURE_FILE([sbflows]) - - # Send ip packets between the two ports. -@@ -6123,7 +6197,7 @@ as hv1 ovs-appctl netdev-dummy/receive vif1 $packet - #Disable router R1 - ovn-nbctl --wait=hv set Logical_Router R1 enabled=false - --ovs-sbctl dump-flows > sbflows2 -+ovn-sbctl dump-flows > sbflows2 - AT_CAPTURE_FILE([sbflows2]) - - as hv1 ovs-appctl netdev-dummy/receive vif1 $packet -@@ -6758,13 +6832,7 @@ test_dhcp() { - } - - compare_dhcp_packets() { -- received=$($PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif$1-tx.pcap) -- expected=$(cat $1.expected) -- -- if test "$received" != "$expected"; then -- AT_CHECK_UNQUOTED([echo "$received"; tcpdump_hex "$received"], [0], -- [$(echo "$expected"; tcpdump_hex "$expected")]) -- fi -+ OVN_CHECK_PACKETS([hv1/vif$1-tx.pcap], [$1.expected]) - } - - AT_CAPTURE_FILE([sbflows]) -@@ -6962,8 +7030,9 @@ expected_dhcp_opts=0 - test_dhcp 11 2 f00000000002 07 0 $ciaddr $offer_ip $request_ip 0 0 ff1000000001 - - # There is no reply for this. Check for the INFO log in ovn-controller.log --AT_CHECK([test 1 = $(cat hv1/ovn-controller.log | \ --grep "DHCPRELEASE f0:00:00:00:00:02 10.0.0.6" -c)]) -+OVS_WAIT_UNTIL( -+ [test 1 = $(cat hv1/ovn-controller.log | grep "DHCPRELEASE f0:00:00:00:00:02 10.0.0.6" -c) -+]) - - $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets - AT_CHECK([cat 2.packets], [0], []) -@@ -7120,7 +7189,9 @@ ciaddr=`ip_to_hex 0 0 0 0` - request_ip=0 - expected_dhcp_opts="" - test_dhcp 18 1 f00000000001 04 0 $ciaddr $offer_ip $request_ip 0 0 ff1000000001 $server_ip 02 $expected_dhcp_opts --AT_CHECK([grep -F -iq 'DHCPDECLINE from f0:00:00:00:00:01, 10.0.0.4 duplicated' hv1/ovn-controller.log], [0], []) -+OVS_WAIT_UNTIL( -+ [test 1 -le $(grep -F -i -c 'DHCPDECLINE from f0:00:00:00:00:01, 10.0.0.4 duplicated' hv1/ovn-controller.log) -+]) - - # Send Etherboot. - -@@ -7138,7 +7209,7 @@ ovn-nbctl dhcp-options-set-options $d3 \ - lease_time=3600 router=10.0.0.1 bootfile_name_alt=\"bootfile_name_alt\" \ - bootfile_name=\"bootfile\" - --ovn-nbctl lsp-set-dhcpv4-options ls1-lp1 $d3 -+ovn-nbctl --wait=hv lsp-set-dhcpv4-options ls1-lp1 $d3 - - offer_ip=`ip_to_hex 10 0 0 4` - server_ip=`ip_to_hex 10 0 0 1` -@@ -7156,9 +7227,6 @@ compare_dhcp_packets 1 - as northd - OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE]) - --as northd-backup --OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE]) -- - northd_version=$(ovn-sbctl get SB_Global . options:northd_internal_version | sed s/\"//g) - echo "northd version = $northd_version" - -@@ -7295,10 +7363,6 @@ check ovn-nbctl --wait=hv sync - # Start with 0 because the first request will not have NXT_RESUME - n_resume=0 - --trim_zeros() { -- sed 's/\(00\)\{1,\}$//' --} -- - # This shell function sends a DHCPv6 request packet - # test_dhcpv6 INPORT SRC_MAC SRC_LLA DHCPv6_MSG_TYPE OFFER_IP OUTPORT... - # The OUTPORTs (zero or more) list the VIFs on which the original DHCPv6 -@@ -7400,12 +7464,8 @@ test_dhcpv6_release() { - check_packets() { - local port=$1 - -- $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif$port-tx.pcap | trim_zeros > $port.packets - # Skipping UDP checksum -- cat $port.expected | cut -c 1-120,125- > expout -- AT_CHECK([cat $port.packets | cut -c 1-120,125- ], [0], [expout]) -- -- rm $port.packets -+ OVN_CHECK_PACKETS([hv1/vif$port-tx.pcap], [$port.expected], ["trim_zeros | cut -c 1-120,125-"]) - rm $port.expected - } - -@@ -7508,7 +7568,7 @@ ovn-nbctl dhcp-options-set-options $d1 \ - server_id=00:00:00:10:00:01 \ - bootfile_name_alt=\"bootfile_name_alt\" \ - bootfile_name=\"bootfile_name\" --ovn-nbctl lsp-set-dhcpv6-options ls1-lp2 ${d1} -+ovn-nbctl --wait=hv lsp-set-dhcpv6-options ls1-lp2 ${d1} - - reset_pcap_file hv1-vif2 hv1/vif2 - -@@ -7645,6 +7705,9 @@ ovn-nbctl lsp-add alice alice1 \ - wait_for_ports_up - check ovn-nbctl --wait=hv sync - -+OVN_WAIT_REMOTE_OUTPUT_FLOWS(["hv1"],["hv2"]) -+OVN_WAIT_REMOTE_OUTPUT_FLOWS(["hv2"],["hv1"]) -+ - # Send ip packets between foo1 and alice1 - src_mac="f00000010203" - dst_mac="000001010203" -@@ -8418,6 +8481,7 @@ check_dynamic_addresses() { - check_row_count nb:Logical_Switch_Port 1 name="$1" dynamic_addresses="$arg" - } - -+check ovn-nbctl --wait=sb sync - # Add a port to a switch that does not have a subnet set, then set the - # subnet which should result in an address being allocated for the port. - ovn-nbctl --wait=hv set NB_Global . options:mac_prefix="0a:00:00:00:00:00" -@@ -8733,7 +8797,7 @@ OVN_FOR_EACH_NORTHD([ - AT_SETUP([ipam connectivity]) - ovn_start - --ovn-nbctl lr-add R1 -+ovn-nbctl --wait=sb lr-add R1 - - # Test for a ping using dynamically allocated addresses. - ovn-nbctl --wait=hv set NB_Global . options:mac_prefix="0a:00:00:00:00:00" -@@ -9019,10 +9083,6 @@ packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111 - # Send IP packet destined to 8.8.8.8 from lsp1lp2 - as hv1 ovs-appctl netdev-dummy/receive hv1-ls1lp2 $packet - --trim_zeros() { -- sed 's/\(00\)\{1,\}$//' --} -- - # ARP packet should be received with Target IP Address set to 192.168.1.254 and - # not 8.8.8.8 - -@@ -9078,9 +9138,6 @@ AT_CAPTURE_FILE([sbflows]) - - # Wait for packet to be received. - OVS_WAIT_UNTIL([test `wc -c < "hv1/snoopvif-tx.pcap"` -ge 140]) --trim_zeros() { -- sed 's/\(00\)\{1,\}$//' --} - $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap | trim_zeros |sort | uniq > packets - AT_CHECK([sort packets], [0], [dnl - fffffffffffff0000000000108060001080006040001f00000000001c0a80001000000000000c0a80001 -@@ -9277,9 +9334,6 @@ ovn-nbctl list logical_router_port lrp0 - ovn-nbctl show - # Wait for packet to be received. - OVS_WAIT_UNTIL([test `wc -c < "hv1/snoopvif-tx.pcap"` -ge 50]) --trim_zeros() { -- sed 's/\(00\)\{1,\}$//' --} - $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap | trim_zeros | sort | uniq > packets - expected="fffffffffffff0000000000108060001080006040001f00000000001c0a80001000000000000c0a80001" - echo $expected > expout -@@ -9300,9 +9354,6 @@ ovn-nbctl lsp-set-options lrp0-rp router-port=lrp0 nat-addresses="router" exclud - - # Wait for packets to be received. - OVS_WAIT_UNTIL([test `wc -c < "hv1/snoopvif-tx.pcap"` -ge 250]) --trim_zeros() { -- sed 's/\(00\)\{1,\}$//' --} - - $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap | trim_zeros > packets - g0="fffffffffffff0000000000108060001080006040001f00000000001c0a80001000000000000c0a80001" -@@ -10721,10 +10772,6 @@ OVN_POPULATE_ARP - wait_for_ports_up - check ovn-nbctl --wait=hv sync - --trim_zeros() { -- sed 's/\(00\)\{1,\}$//' --} -- - # Send ip packets between foo1 and bar1 - # (East-west traffic should flow normally) - src_mac="f00000010203" -@@ -11004,12 +11051,9 @@ test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $d - # NXT_RESUMEs should be 1. - OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets --cat 1.expected | cut -c -48 > expout --AT_CHECK([cat 1.packets | cut -c -48], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected], ["cut -c -48"]) - # Skipping the IPv4 checksum. --cat 1.expected | cut -c 53- > expout --AT_CHECK([cat 1.packets | cut -c 53-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected], ["cut -c 53-"]) - - reset_pcap_file hv1-vif1 hv1/vif1 - reset_pcap_file hv1-vif2 hv1/vif2 -@@ -11026,12 +11070,9 @@ test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $d - # NXT_RESUMEs should be 2. - OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets --cat 2.expected | cut -c -48 > expout --AT_CHECK([cat 2.packets | cut -c -48], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [2.expected], ["cut -c -48"]) - # Skipping the IPv4 checksum. --cat 2.expected | cut -c 53- > expout --AT_CHECK([cat 2.packets | cut -c 53-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [2.expected], ["cut -c 53-"]) - - reset_pcap_file hv1-vif1 hv1/vif1 - reset_pcap_file hv1-vif2 hv1/vif2 -@@ -11049,12 +11090,9 @@ test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $d - # NXT_RESUMEs should be 3. - OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets --cat 2.expected | cut -c -48 > expout --AT_CHECK([cat 2.packets | cut -c -48], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [2.expected], ["cut -c -48"]) - # Skipping the IPv4 checksum. --cat 2.expected | cut -c 53- > expout --AT_CHECK([cat 2.packets | cut -c 53-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [2.expected], ["cut -c 53-"]) - - reset_pcap_file hv1-vif1 hv1/vif1 - reset_pcap_file hv1-vif2 hv1/vif2 -@@ -11131,12 +11169,9 @@ test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $d - # NXT_RESUMEs should be 5. - OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets --cat 2.expected | cut -c -48 > expout --AT_CHECK([cat 2.packets | cut -c -48], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [2.expected], ["cut -c -48"]) - # Skipping the IPv4 checksum. --cat 2.expected | cut -c 53- > expout --AT_CHECK([cat 2.packets | cut -c 53-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [2.expected], ["cut -c 53-"]) - - reset_pcap_file hv1-vif1 hv1/vif1 - reset_pcap_file hv1-vif2 hv1/vif2 -@@ -11154,12 +11189,9 @@ test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $d - # NXT_RESUMEs should be 6. - OVS_WAIT_UNTIL([test 6 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets --cat 2.expected | cut -c -48 > expout --AT_CHECK([cat 2.packets | cut -c -48], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [2.expected], ["cut -c -48"]) - # Skipping the IPv4 checksum. --cat 2.expected | cut -c 53- > expout --AT_CHECK([cat 2.packets | cut -c 53-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [2.expected], ["cut -c 53-"]) - - reset_pcap_file hv1-vif1 hv1/vif1 - reset_pcap_file hv1-vif2 hv1/vif2 -@@ -11221,12 +11253,9 @@ test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $d - # NXT_RESUMEs should be 9. - OVS_WAIT_UNTIL([test 9 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets --cat 1.expected | cut -c -48 > expout --AT_CHECK([cat 1.packets | cut -c -48], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected], ["cut -c -48"]) - # Skipping the IPv4 checksum. --cat 1.expected | cut -c 53- > expout --AT_CHECK([cat 1.packets | cut -c 53-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected], ["cut -c 53-"]) - - reset_pcap_file hv1-vif1 hv1/vif1 - reset_pcap_file hv1-vif2 hv1/vif2 -@@ -11244,10 +11273,8 @@ test_dns6 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $ - # NXT_RESUMEs should be 10 - OVS_WAIT_UNTIL([test 10 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets - # Skipping the UDP checksum. --cat 1.expected | cut -c 1-120,125- > expout --AT_CHECK([cat 1.packets | cut -c 1-120,125-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected], ["cut -c 1-120,125-"]) - - reset_pcap_file hv1-vif1 hv1/vif1 - reset_pcap_file hv1-vif2 hv1/vif2 -@@ -11273,12 +11300,9 @@ test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $d - # NXT_RESUMEs should be 11. - OVS_WAIT_UNTIL([test 11 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets --cat 1.expected | cut -c -48 > expout --AT_CHECK([cat 1.packets | cut -c -48], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected], ["cut -c -48"]) - # Skipping the IPv4 checksum. --cat 1.expected | cut -c 53- > expout --AT_CHECK([cat 1.packets | cut -c 53-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected], ["cut -c 53-"]) - - reset_pcap_file hv1-vif1 hv1/vif1 - reset_pcap_file hv1-vif2 hv1/vif2 -@@ -11296,12 +11320,9 @@ test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $d - # NXT_RESUMEs should be 12. - OVS_WAIT_UNTIL([test 12 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets --cat 1.expected | cut -c -48 > expout --AT_CHECK([cat 1.packets | cut -c -48], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected], ["cut -c -48"]) - # Skipping the IPv4 checksum. --cat 1.expected | cut -c 53- > expout --AT_CHECK([cat 1.packets | cut -c 53-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected], ["cut -c 53-"]) - - reset_pcap_file hv1-vif1 hv1/vif1 - reset_pcap_file hv1-vif2 hv1/vif2 -@@ -11313,6 +11334,57 @@ OVN_CLEANUP([hv1]) - AT_CLEANUP - ]) - -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([dns lookup : EDNS]) -+OVN_CHECK_SCAPY_EDNS_CLIENT_SUBNET_SUPPORT() -+ovn_start -+ -+check ovn-nbctl ls-add ls \ -+ -- lsp-add ls lsp \ -+ -- lsp-set-addresses lsp "00:00:00:00:00:01 10.0.0.1" -+ -+d=$(ovn-nbctl create dns records={}) -+ -+check ovn-nbctl set dns $d records:foo.ovn.org="10.0.0.42" -+check ovn-nbctl set Logical_switch ls dns_records="$d" -+ -+net_add n1 -+sim_add hv1 -+ -+as hv1 -+ovs-vsctl add-br br-phys -+ovn_attach n1 br-phys 192.168.0.1 -+check ovs-vsctl add-port br-int hv1-vif1 -- \ -+ set interface hv1-vif1 external-ids:iface-id=lsp \ -+ options:tx_pcap=hv1/vif1-tx.pcap \ -+ options:rxq_pcap=hv1/vif1-rx.pcap -+ -+OVN_POPULATE_ARP -+wait_for_ports_up -+check ovn-nbctl --wait=hv sync -+ -+dns_req=$(fmt_pkt "Ether(dst='00:00:00:00:00:02', src='00:00:00:00:00:01') / \ -+ IP(dst='10.0.0.254', src='10.0.0.1') / \ -+ UDP(sport=42424, dport=53) / \ -+ DNS(rd=1, qd=DNSQR(qname='foo.ovn.org'), arcount=1, ar=[ \ -+ DNSRR(type='OPT', rclass=4096, \ -+ rdata=EDNS0ClientSubnet(source_plen=24, \ -+ address='10.0.0.1'))])") -+dns_reply=$(fmt_pkt "Ether(dst='00:00:00:00:00:01', src='00:00:00:00:00:02') / \ -+ IP(dst='10.0.0.1', src='10.0.0.254') / \ -+ UDP(sport=53, dport=42424,chksum=0) / \ -+ DNS(qr=1, qd=DNSQR(qname='foo.ovn.org'), \ -+ an=DNSRR(rrname='foo.ovn.org', type='A', ttl=3600, \ -+ rdata='10.0.0.42'))") -+echo ${dns_reply} > expected -+ -+as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 ${dns_req} -+OVN_CHECK_PACKETS_REMOVE_BROADCAST([hv1/vif1-tx.pcap], [expected]) -+ -+OVN_CLEANUP([hv1]) -+AT_CLEANUP -+]) -+ - OVN_FOR_EACH_NORTHD([ - AT_SETUP([4 HV, 1 LS, 1 LR, packet test with HA distributed router gateway port]) - ovn_start -@@ -11481,30 +11553,7 @@ test_ip_packet() - # Resend packet from foo1 to outside1 - check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet - -- AT_CAPTURE_FILE([exp]) -- AT_CAPTURE_FILE([rcv]) -- check_packets() { -- > exp -- > rcv -- -- pcap=ext1/vif1-tx.pcap -- type=ext1-vif1.expected -- echo "--- $pcap" | tee -a exp >> rcv -- sort -u "$type" >> exp -- $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" $pcap | sort -u >> rcv -- echo | tee -a exp >> rcv -- -- pcap=$active_gw/br-phys_n1-tx.pcap -- echo "--- $pcap" | tee -a exp >> rcv -- sort -u "$type" >> exp -- $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" $pcap > packets -- (grep "$expected" packets; grep "$exp_gw_ip_garp" packets) | sort -u >> rcv -- echo | tee -a exp >> rcv -- -- $at_diff exp rcv >/dev/null -- } -- -- OVS_WAIT_UNTIL([check_packets], [$at_diff -F'^---' exp rcv]) -+ OVN_CHECK_PACKETS_CONTAIN([ext1/vif1-tx.pcap], [ext1-vif1.expected]) - - if test $backup_vswitchd_dead != 1; then - # Check for backup gw only if vswitchd is alive -@@ -12206,9 +12255,6 @@ OVN_WAIT_PATCH_PORT_FLOWS(["ln_port"], ["hv2"]) - - # Wait for packets to be received. - OVS_WAIT_UNTIL([test `wc -c < "hv1/snoopvif-tx.pcap"` -ge 100]) --trim_zeros() { -- sed 's/\(00\)\{1,\}$//' --} - $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap | trim_zeros > packets - expected="fffffffffffff0000000000108060001080006040001f00000000001c0a80001000000000000c0a80001" - echo $expected > expout -@@ -12240,21 +12286,12 @@ OVN_WAIT_PATCH_PORT_FLOWS(["ln_port"], ["hv3"]) - # Re-add nat-addresses option - ovn-nbctl lsp-set-options lrp0-rp router-port=lrp0 nat-addresses="router" - --# Wait for packets to be received. --OVS_WAIT_UNTIL([test `wc -c < "hv1/snoopvif-tx.pcap"` -ge 250]) --trim_zeros() { -- sed 's/\(00\)\{1,\}$//' --} -- --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap | trim_zeros | sort | uniq > packets - garp_1="fffffffffffff0000000000308060001080006040001f00000000003c0a80003000000000000c0a80003" --echo $garp_1 > expout -+echo $garp_1 > expected_out - garp_2="fffffffffffff0000000000408060001080006040001f00000000004c0a80004000000000000c0a80004" --echo $garp_2 >> expout -+echo $garp_2 >> expected_out - --cat packets | grep $garp_1 | head -1 > exp --cat packets | grep $garp_2 | head -1 >> exp --AT_CHECK([cat exp], [0], [expout]) -+OVN_CHECK_PACKETS_CONTAIN([hv1/snoopvif-tx.pcap], [expected_out], "trim_zeros") - - OVN_CLEANUP([hv1],[hv2],[hv3]) - -@@ -12577,6 +12614,7 @@ AT_CLEANUP - - OVN_FOR_EACH_NORTHD([ - AT_SETUP([IPv6 ND Router Solicitation responder]) -+AT_SKIP_IF([test $HAVE_SCAPY = no]) - AT_KEYWORDS([ovn-nd_ra]) - ovn_start - -@@ -12643,76 +12681,120 @@ ovs-vsctl -- add-port br-int hv1-vif3 -- \ - wait_for_ports_up - check ovn-nbctl --wait=hv sync - -+n_resume=1 -+ - # Make sure that ovn-controller has installed the corresponding OF Flow. - OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`]) - - # This shell function sends a Router Solicitation packet. --# test_ipv6_ra INPORT SRC_MAC SRC_LLA ADDR_MODE MTU RA_PREFIX_OPT RDNSS DNSSL ROUTE_INFO -+# test_ipv6_ra INPORT SRC_MAC SRC_LLA RA_OPT MTU PREFIX RDNSS DNSSL ROUTES - test_ipv6_ra() { -- local inport=$1 src_mac=$2 src_lla=$3 addr_mode=$4 mtu=$5 prefix_opt=$6 -- local rdnss=$7 dnssl=$8 route_info=$9 -- local request=333300000002${src_mac}86dd6000000000103aff${src_lla}ff02000000000000000000000000000285000efc000000000101${src_mac} -+ local inport=$1 src_mac=$2 src_ip=$3 ra=$4 mtu=$5 prefix=$6 -+ local rdnss=$7 dnssl=$8 routes=$9 - -- local len=24 -- local mtu_opt="" -- if test $mtu != 0; then -- len=`expr $len + 8` -- mtu_opt=05010000${mtu} -+ local request=$(fmt_pkt "Ether(dst='33:33:00:00:00:02', src='${src_mac}')/ \ -+ IPv6(dst='ff02::2', src='${src_ip}')/ \ -+ ICMPv6ND_RS()/ \ -+ ICMPv6NDOptSrcLLAddr(lladdr='${src_mac}')") -+ -+ local reply_dst=$src_ip -+ if test "${reply_dst}" = "::"; then -+ reply_dst="ff02::1" - fi - -- if test ${#rdnss} != 0; then -- len=`expr $len + ${#rdnss} / 2` -+ local rep_scapy="Ether(dst='${src_mac}', src='fa:16:3e:00:00:01')/ \ -+ IPv6(dst='${reply_dst}', src='fe80::f816:3eff:fe00:1')/ \ -+ ${ra}/ \ -+ ICMPv6NDOptSrcLLAddr(lladdr='fa:16:3e:00:00:01')" -+ -+ if test "${mtu}" != "0"; then -+ rep_scapy="${rep_scapy}/ICMPv6NDOptMTU(mtu=${mtu})" - fi - -- if test ${#dnssl} != 0; then -- len=`expr $len + ${#dnssl} / 2` -+ if test -n "${rdnss}"; then -+ rep_scapy="${rep_scapy}/ICMPv6NDOptRDNSS(dns=[['${rdnss}']])" - fi - -- if test ${#route_info} != 0; then -- len=`expr $len + ${#route_info} / 2` -+ if test -n "${dnssl}"; then -+ rep_scapy="${rep_scapy}/ICMPv6NDOptDNSSL(searchlist=[['${dnssl}']])" - fi - -- if test ${#prefix_opt} != 0; then -- prefix_opt=${prefix_opt}fdad1234567800000000000000000000 -- len=`expr $len + ${#prefix_opt} / 2` -+ if test -n "${routes}"; then -+ rep_scapy="${rep_scapy}/${routes}" - fi - -- len=$(printf "%x" $len) -- local lrp_mac=fa163e000001 -- local lrp_lla=fe80000000000000f8163efffe000001 -- local reply=${src_mac}${lrp_mac}86dd6000000000${len}3aff${lrp_lla}${src_lla}8600XXXXff${addr_mode}ffff00000000000000000101${lrp_mac}${mtu_opt}${rdnss}${dnssl}${route_info}${prefix_opt} -+ if test -n "${prefix}"; then -+ local a_flag=$(echo $ra | grep -vc "M=1") -+ rep_scapy="${rep_scapy}/ICMPv6NDOptPrefixInfo(prefix='${prefix}', A=${a_flag})" -+ fi -+ -+ local reply=$(fmt_pkt "${rep_scapy}") - echo $reply >> $inport.expected - - as hv1 ovs-appctl netdev-dummy/receive hv1-vif${inport} $request -+ -+ OVS_WAIT_UNTIL([test $n_resume = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) -+ n_resume=$((n_resume + 1)) -+} -+ -+check_packets() { -+ local port=$1 -+ -+ # Skipping UDP checksum -+ OVN_CHECK_PACKETS([hv1/vif$port-tx.pcap], [$port.expected], ["cut -c 1-112,117-"]) -+ -+ rm $port.packets -+ rm $port.expected -+ -+ reset_pcap_file hv1-vif1 hv1/vif1 -+ reset_pcap_file hv1-vif2 hv1/vif2 -+ reset_pcap_file hv1-vif3 hv1/vif3 -+} -+ -+prepare_ra_opt() { -+ local mode=$1 priority=$2 -+ -+ if test "${mode}" = "stateful"; then -+ echo "ICMPv6ND_RA(chlim=255, routerlifetime=65535, M=1, prf=${priority})" -+ elif test "${mode}" = "stateless"; then -+ echo "ICMPv6ND_RA(chlim=255, routerlifetime=65535, O=1, prf=${priority})" -+ else -+ echo "ICMPv6ND_RA(chlim=255, routerlifetime=65535, prf=${priority})" -+ fi -+} -+ -+prepare_route_opt() { -+ local prefix=$1 priority=$2 plen=$3 -+ -+ local len=2 -+ if test $plen -gt 64; then -+ len=3 -+ fi -+ -+ echo "ICMPv6NDOptRouteInfo(len=$len, prf=${priority}, prefix='${prefix}', plen=$plen)" - } - - AT_CAPTURE_FILE([ofctl_monitor0.log]) - as hv1 ovs-ofctl monitor br-int resume --detach --no-chdir \ - --pidfile=ovs-ofctl0.pid 2> ofctl_monitor0.log - --# MTU is not set and the address mode is set to slaac --addr_mode=00 --default_prefix_option_config=030440c0ffffffffffffffff00000000 --src_mac=fa163e000002 --src_lla=fe80000000000000f8163efffe000002 --test_ipv6_ra 1 $src_mac $src_lla $addr_mode 0 $default_prefix_option_config -+prefix="fdad:1234:5678::" - --# NXT_RESUME should be 1. --OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) -+# MTU is not set and the address mode is set to slaac -+ra=$(prepare_ra_opt "" 0) -+src_mac="fa:16:3e:00:00:02" -+src_lla="fe80::f816:3eff:fe00:2" - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets -+test_ipv6_ra 1 $src_mac $src_lla "$ra" 0 $prefix "" "" "" -+check_packets 1 - --cat 1.expected | cut -c -112 > expout --AT_CHECK([cat 1.packets | cut -c -112], [0], [expout]) -+# Check with RA with src being "::". -+ovn-nbctl --wait=hv lsp-set-port-security lp1 "" - --# Skipping the ICMPv6 checksum. --cat 1.expected | cut -c 117- > expout --AT_CHECK([cat 1.packets | cut -c 117-], [0], [expout]) -+test_ipv6_ra 1 $src_mac "::" "$ra" 0 $prefix "" "" "" -+check_packets 1 - --rm -f *.expected --reset_pcap_file hv1-vif1 hv1/vif1 --reset_pcap_file hv1-vif2 hv1/vif2 --reset_pcap_file hv1-vif3 hv1/vif3 -+ovn-nbctl --wait=hv lsp-set-port-security lp1 "fa:16:3e:00:00:02 10.0.0.12 fdad:1234:5678:0:f816:3eff:fe:2" - - # Set the MTU to 1500, send_periodic to false, preference to LOW - ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:mtu=1500 -@@ -12726,33 +12808,14 @@ ovn-nbctl --wait=hv set Logical_Router_port lrp0 ipv6_ra_configs:route_info=HIGH - OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`]) - - # addr_mode byte also includes router preference information --addr_mode=18 --default_prefix_option_config=030440c0ffffffffffffffff00000000 --src_mac=fa163e000003 --src_lla=fe80000000000000f8163efffe000003 --mtu=000005dc --rdnss=19030000ffffffff10000000000000000000000000000011 --dnssl=1f030000ffffffff02616102626202636300000000000000 --route_info=18023008ffffffff100100000000000018036018ffffffff10020000000000000000000000000000 -- --test_ipv6_ra 2 $src_mac $src_lla $addr_mode $mtu $default_prefix_option_config $rdnss $dnssl $route_info -- --# NXT_RESUME should be 2. --OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) -- --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets -- --cat 2.expected | cut -c -112 > expout --AT_CHECK([cat 2.packets | cut -c -112], [0], [expout]) -+ra=$(prepare_ra_opt "" 3) -+routes=$(prepare_route_opt '1001::' 1 48) -+routes="${routes}/$(prepare_route_opt '1002::' 3 96)" -+src_mac="fa:16:3e:00:00:03" -+src_lla="fe80::f816:3eff:fe00:3" - --# Skipping the ICMPv6 checksum. --cat 2.expected | cut -c 117- > expout --AT_CHECK([cat 2.packets | cut -c 117-], [0], [expout]) -- --rm -f *.expected --reset_pcap_file hv1-vif1 hv1/vif1 --reset_pcap_file hv1-vif2 hv1/vif2 --reset_pcap_file hv1-vif3 hv1/vif3 -+test_ipv6_ra 2 $src_mac $src_lla "$ra" 1500 $prefix "1000::11" "aa.bb.cc" "$routes" -+check_packets 2 - - # Set the address mode to dhcpv6_stateful, router_preference to HIGH - ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:address_mode=dhcpv6_stateful -@@ -12763,30 +12826,12 @@ ovn-nbctl --wait=hv remove Logical_Router_Port lrp0 ipv6_ra_configs route_info - OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`]) - - # addr_mode byte also includes router preference information --addr_mode=88 --default_prefix_option_config=03044080ffffffffffffffff00000000 --src_mac=fa163e000004 --src_lla=fe80000000000000f8163efffe000004 --mtu=000005dc -- --test_ipv6_ra 3 $src_mac $src_lla $addr_mode $mtu $default_prefix_option_config "" $dnssl -- --# NXT_RESUME should be 3. --OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) -+ra=$(prepare_ra_opt "stateful" 1) -+src_mac="fa:16:3e:00:00:04" -+src_lla="fe80::f816:3eff:fe00:4" - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif3-tx.pcap > 3.packets -- --cat 3.expected | cut -c -112 > expout --AT_CHECK([cat 3.packets | cut -c -112], [0], [expout]) -- --# Skipping the ICMPv6 checksum. --cat 3.expected | cut -c 117- > expout --AT_CHECK([cat 3.packets | cut -c 117-], [0], [expout]) -- --rm -f *.expected --reset_pcap_file hv1-vif1 hv1/vif1 --reset_pcap_file hv1-vif2 hv1/vif2 --reset_pcap_file hv1-vif3 hv1/vif3 -+test_ipv6_ra 3 $src_mac $src_lla "$ra" 1500 $prefix "" "aa.bb.cc" "" -+check_packets 3 - - # Set the address mode to dhcpv6_stateless, reset router preference to default - ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:address_mode=dhcpv6_stateless -@@ -12795,46 +12840,27 @@ ovn-nbctl --wait=hv remove Logical_Router_Port lrp0 ipv6_ra_configs dnssl - # Make sure that ovn-controller has installed the corresponding OF Flow. - OVS_WAIT_UNTIL([test 1 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`]) - --addr_mode=40 --default_prefix_option_config=030440c0ffffffffffffffff00000000 --src_mac=fa163e000002 --src_lla=fe80000000000000f8163efffe000002 --mtu=000005dc -- --test_ipv6_ra 1 $src_mac $src_lla $addr_mode $mtu $default_prefix_option_config -+ra=$(prepare_ra_opt "stateless" 0) -+src_mac="fa:16:3e:00:00:02" -+src_lla="fe80::f816:3eff:fe00:2" - --# NXT_RESUME should be 4. --OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) -- --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets -- --cat 1.expected | cut -c -112 > expout --AT_CHECK([cat 1.packets | cut -c -112], [0], [expout]) -- --# Skipping the ICMPv6 checksum. --cat 1.expected | cut -c 117- > expout --AT_CHECK([cat 1.packets | cut -c 117-], [0], [expout]) -- --rm -f *.expected --reset_pcap_file hv1-vif1 hv1/vif1 --reset_pcap_file hv1-vif2 hv1/vif2 --reset_pcap_file hv1-vif3 hv1/vif3 -+test_ipv6_ra 1 $src_mac $src_lla "$ra" 1500 $prefix "" "" "" -+check_packets 1 - - # Set the address mode to invalid. - ovn-nbctl --wait=hv set Logical_Router_Port lrp0 ipv6_ra_configs:address_mode=invalid - # Make sure that ovn-controller has not installed any OF Flow for IPv6 ND RA. - OVS_WAIT_UNTIL([test 0 = `as hv1 ovs-ofctl dump-flows br-int | grep -c "ipv6_dst=ff02::2,nw_ttl=255,icmp_type=133,icmp_code=0"`]) - --addr_mode=40 --default_prefix_option_config="" --src_mac=fa163e000002 --src_lla=fe80000000000000f8163efffe000002 --mtu=000005dc -+ra=$(prepare_ra_opt "stateless" 0) - --test_ipv6_ra 1 $src_mac $src_lla $addr_mode $mtu $default_prefix_option_config -+src_mac="fa:16:3e:00:00:02" -+src_lla="fe80::f816:3eff:fe00:2" - --# NXT_RESUME should be 4 only. --OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) -+# This shouldn't produce any NXT_RESUME. -+n_resume=$((n_resume - 1)) -+ -+test_ipv6_ra 1 $src_mac $src_lla "$ra" 1500 "" "" "" "" - - $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets - AT_CHECK([cat 1.packets], [0], []) -@@ -13612,7 +13638,7 @@ for chassis in gw1 hv1 hv2; do - echo "checking gw2 -> $chassis" - OVS_WAIT_UNTIL([ - bfd_cfg=$(ovs-vsctl --bare --columns bfd find Interface name=ovn-$chassis-0) -- test "$bfd_cfg" = "enable=true min_rx=2000" -+ test "$bfd_cfg" = "check_tnl_key=true enable=true min_rx=2000" - ]) - done - ovn-nbctl --wait=hv set NB_Global . options:"bfd-min-tx"=1500 -@@ -13620,7 +13646,7 @@ for chassis in gw1 hv1 hv2; do - echo "checking gw2 -> $chassis" - OVS_WAIT_UNTIL([ - bfd_cfg=$(ovs-vsctl --bare --columns bfd find Interface name=ovn-$chassis-0) -- test "$bfd_cfg" = "enable=true min_rx=2000 min_tx=1500" -+ test "$bfd_cfg" = "check_tnl_key=true enable=true min_rx=2000 min_tx=1500" - ]) - done - ovn-nbctl remove NB_Global . options "bfd-min-rx" -@@ -13629,7 +13655,7 @@ for chassis in gw1 hv1 hv2; do - echo "checking gw2 -> $chassis" - OVS_WAIT_UNTIL([ - bfd_cfg=$(ovs-vsctl --bare --columns bfd find Interface name=ovn-$chassis-0) -- test "$bfd_cfg" = "enable=true min_tx=1500 mult=15" -+ test "$bfd_cfg" = "check_tnl_key=true enable=true min_tx=1500 mult=15" - ]) - done - -@@ -13879,33 +13905,15 @@ as hv1 reset_pcap_file snoopvif hv1/snoopvif - # add nat-addresses option - ovn-nbctl --wait=hv lsp-set-options lrp0-rp router-port=lrp0 nat-addresses="router" - --# Wait for packets to be received through hv2. --OVS_WAIT_UNTIL([test `wc -c < "hv1/snoopvif-tx.pcap"` -ge 100]) --trim_zeros() { -- sed 's/\(00\)\{1,\}$//' --} -- - only_broadcast_from_lrp1() { - grep "fffffffffffff00000000001" - } - - garp="fffffffffffff0000000000108060001080006040001f00000000001c0a80064000000000000c0a80064" --echo $garp > expout -+echo $garp > expected_out - --OVS_WAIT_UNTIL( -- [$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap > rcv_text -- exp_rcvd=$(cat rcv_text | grep $garp | wc -l) -- echo "expected received = $exp_rcvd" -- test $exp_rcvd -ge 1]) -- --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv1_snoop_tx --echo "packets on hv1-snoopvif:" --cat hv1_snoop_tx --AT_CHECK([sort hv1_snoop_tx], [0], [expout]) --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv2/br-phys_n1-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv2_br_phys_tx --echo "packets on hv2 br-phys tx" --cat hv2_br_phys_tx --AT_CHECK([grep $garp hv2_br_phys_tx | sort], [0], [expout]) -+OVN_CHECK_PACKETS_CONTAIN([hv1/snoopvif-tx.pcap], [expected_out], "trim_zeros") -+OVN_CHECK_PACKETS_CONTAIN([hv2/br-phys_n1-tx.pcap], [expected_out], "trim_zeros") - $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv3/br-phys_n1-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv3_br_phys_tx - echo "packets on hv3 br-phys tx" - cat hv3_br_phys_tx -@@ -13914,9 +13922,6 @@ AT_CHECK([grep $garp hv3_br_phys_tx | sort], [0], []) - - # at this point, we invert the priority of the gw chassis between hv2 and hv3 - --# Reset hv2/br-phys_n1 before inverting gw chassis, as otherwise packets might --# be reset (while not resetting hv1/snoopvif because not yet sent). --as hv2 reset_pcap_file br-phys_n1 hv2/br-phys_n1 - ovn-nbctl --wait=hv \ - --id=@gc0 create Gateway_Chassis \ - name=outside_gw1 chassis_name=hv2 priority=1 -- \ -@@ -13924,24 +13929,17 @@ ovn-nbctl --wait=hv \ - name=outside_gw2 chassis_name=hv3 priority=10 -- \ - set Logical_Router_Port lrp0 'gateway_chassis=[@gc0,@gc1]' - -+# We expect not to receive garp on hv2 after inverting the priority. -+# Hence reset hv2 after inverting priority as otherwise a garp might -+# be received on hv2 between the reset and the priority change. -+ -+as hv2 reset_pcap_file br-phys_n1 hv2/br-phys_n1 - as hv3 reset_pcap_file br-phys_n1 hv3/br-phys_n1 - as hv1 reset_pcap_file snoopvif hv1/snoopvif - --trim_zeros() { -- sed 's/\(00\)\{1,\}$//' --} -- --# Wait for packets to be received. --OVS_WAIT_UNTIL( -- [$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap > rcv_text -- exp_rcvd=$(cat rcv_text | grep $garp | wc -l) -- echo "expected received = $exp_rcvd" -- test $exp_rcvd -ge 1]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv1_snoopvif_tx --AT_CHECK([sort hv1_snoopvif_tx], [0], [expout]) --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv3/br-phys_n1-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv3_br_phys_tx --AT_CHECK([grep $garp hv3_br_phys_tx | sort], [0], [expout]) -+OVN_CHECK_PACKETS_CONTAIN([hv1/snoopvif-tx.pcap], [expected_out], "trim_zeros") -+OVN_CHECK_PACKETS_CONTAIN([hv3/br-phys_n1-tx.pcap], [expected_out], "trim_zeros") - $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv2/br-phys_n1-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv2_br_phys_tx - AT_CHECK([grep $garp hv2_br_phys_tx | sort], [0], []) - -@@ -13974,25 +13972,11 @@ ovn-nbctl --wait=hv lsp-set-options lrp0-rp router-port=lrp0 nat-addresses="rout - OVS_WAIT_UNTIL([test 1 = `ovn-sbctl --bare --columns nat_addresses find port_binding \ - logical_port=lrp0-rp | grep is_chassis | wc -l`]) - --# Wait for packets to be received. --OVS_WAIT_UNTIL([test `wc -c < "hv1/snoopvif-tx.pcap"` -ge 100]) --trim_zeros() { -- sed 's/\(00\)\{1,\}$//' --} -- - garp="fffffffffffff00000000001810007de08060001080006040001f00000000001c0a80064000000000000c0a80064" --echo $garp > expout -- --OVS_WAIT_UNTIL( -- [$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap > rcv_text -- exp_rcvd=$(cat rcv_text | grep $garp | wc -l) -- echo "expected received = $exp_rcvd" -- test $exp_rcvd -ge 1]) -+echo $garp > expected_out - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv1_snoopvif_tx --AT_CHECK([sort hv1_snoopvif_tx], [0], [expout]) --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv3/br-phys_n1-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv3_br_phys_tx --AT_CHECK([grep $garp hv3_br_phys_tx | sort], [0], [expout]) -+OVN_CHECK_PACKETS_CONTAIN([hv1/snoopvif-tx.pcap], [expected_out], "trim_zeros") -+OVN_CHECK_PACKETS_CONTAIN([hv3/br-phys_n1-tx.pcap], [expected_out], "trim_zeros") - $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv2/br-phys_n1-tx.pcap | trim_zeros | only_broadcast_from_lrp1 | uniq > hv2_br_phys_tx - AT_CHECK([grep $garp hv2_br_phys_tx | sort], [0], []) - -@@ -14333,10 +14317,6 @@ wc -l], [0], [4 - chassis_uuid=$(fetch_column Chassis _uuid name=hv1) - wait_row_count Port_Binding 1 logical_port=cr-ip6_public chassis=$chassis_uuid - --trim_zeros() { -- sed 's/\(00\)\{1,\}$//' --} -- - # Test the IPv6 Neighbor Solicitation (NS) - nd_ns action for unknown MAC - # addresses. ovn-controller should generate an IPv6 NS request for IPv6 - # packets whose MAC is unknown (in the ARP_REQUEST router pipeline stage. -@@ -14888,6 +14868,10 @@ wait_column "$hv2_uuid" Port_Binding requested_additional_chassis logical_port=m - # ovn-installed on hv2 should guarantee that. - OVS_WAIT_UNTIL([test `as hv2 ovs-vsctl get Interface migrator external_ids:ovn-installed` = '"true"']) - -+# Still, this does not guarantee that all flows are installed on hv3: hv3 (might) still need to receive and handle -+# additional_chassis for migrator port -+ovn-nbctl --wait=hv sync -+ - # check that... - # unicast from First arrives to hv1:Migrator - # unicast from First arrives to hv2:Migrator -@@ -14974,6 +14958,9 @@ wait_column "" Port_Binding requested_additional_chassis logical_port=migrator - # For instance, migrator port might still be up from prior to complete migration to hv2 - OVS_WAIT_UNTIL([test `as hv2 ovs-vsctl get Interface migrator external_ids:ovn-installed` = '"true"']) - -+# Give time for hv3 to handle the change of Port_Binding for migrator port -+ovn-nbctl --wait=hv sync -+ - # check that... - # unicast from Third doesn't arrive to hv1:Migrator - # unicast from Third arrives to hv2:Migrator -@@ -16135,15 +16122,13 @@ sim_add hv1 - as hv1 - ovs-vsctl add-br br-phys - ovn_attach n1 br-phys 192.168.0.11 --ovs-vsctl -- add-port br-int hv1-vif0 -- \ --set Interface hv1-vif0 ofport-request=1 -+ovs-vsctl -- add-port br-int hv1-vif0 - - sim_add hv2 - as hv2 - ovs-vsctl add-br br-phys - ovn_attach n1 br-phys 192.168.0.12 --ovs-vsctl -- add-port br-int hv2-vif0 -- \ --set Interface hv2-vif0 ofport-request=1 -+ovs-vsctl -- add-port br-int hv2-vif0 - - # Allow only chassis hv1 to bind logical port lsp0. - ovn-nbctl lsp-set-options lsp0 requested-chassis=hv1 -@@ -16151,6 +16136,16 @@ ovn-nbctl lsp-set-options lsp0 requested-chassis=hv1 - # Allow some time for ovn-northd and ovn-controller to catch up. - check ovn-nbctl --wait=hv sync - -+OVS_WAIT_UNTIL([ -+ hv1_ofport=$(as hv1 ovs-vsctl --bare --columns ofport find Interface name=hv1-vif0) -+ test 1 -le $hv1_ofport -+]) -+ -+OVS_WAIT_UNTIL([ -+ hv2_ofport=$(as hv2 ovs-vsctl --bare --columns ofport find Interface name=hv2-vif0) -+ test 1 -le $hv2_ofport -+]) -+ - # Retrieve hv1 and hv2 chassis UUIDs from southbound database - wait_row_count Chassis 1 name=hv1 - wait_row_count Chassis 1 name=hv2 -@@ -16166,7 +16161,7 @@ OVS_WAIT_UNTIL([test 1 = $(grep -c "Not claiming lport lsp0" hv2/ovn-controller. - wait_row_count Port_Binding 1 logical_port=lsp0 'chassis=[[]]' - - # (2) Chassis hv2 should not add flows in OFTABLE_PHY_TO_LOG and OFTABLE_LOG_TO_PHY tables. --AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=0 | grep in_port=1], [1], []) -+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=0 | grep in_port=$hv2_ofport], [1], []) - AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=65 | grep output], [1], []) - - # (3) Chassis hv1 should bind lsp0 when physical to logical mapping exists on hv1. -@@ -16179,8 +16174,8 @@ wait_column "$hv1_uuid" Port_Binding chassis logical_port=lsp0 - - # (4) Chassis hv1 should add flows in OFTABLE_PHY_TO_LOG and OFTABLE_LOG_TO_PHY tables. - as hv1 ovs-ofctl dump-flows br-int --AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=0 | grep in_port=1], [0], [ignore]) --AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=65 | grep actions=output:1], [0], [ignore]) -+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=0 | grep in_port=$hv1_ofport], [0], [ignore]) -+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=65 | grep actions=output:$hv1_ofport], [0], [ignore]) - - # (5) Chassis hv1 should release lsp0 binding and chassis hv2 should bind lsp0 when - # the requested chassis for lsp0 is changed from hv1 to hv2. -@@ -16188,15 +16183,15 @@ echo "verifying that lsp0 binding moves when requested-chassis is changed" - - ovn-nbctl lsp-set-options lsp0 requested-chassis=hv2 - # We might see multiple "Releasing lport ...", when sb is read only --OVS_WAIT_UNTIL([test 1 -le $(grep -c "Releasing lport lsp0 from this chassis" hv1/ovn-controller.log)]) -+OVS_WAIT_UNTIL([test 1 -le $(grep -c "Releasing lport lsp0" hv1/ovn-controller.log)]) - - wait_column "$hv2_uuid" Port_Binding chassis logical_port=lsp0 - - # (6) Chassis hv2 should add flows and hv1 should not. --AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=0 | grep in_port=1], [0], [ignore]) --AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=65 | grep actions=output:1], [0], [ignore]) -+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=0 | grep in_port=$hv2_ofport], [0], [ignore]) -+AT_CHECK([as hv2 ovs-ofctl dump-flows br-int table=65 | grep actions=output:$hv2_ofport], [0], [ignore]) - --AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=0 | grep in_port=1], [1], []) -+AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=0 | grep in_port=$hv1_ofport], [1], []) - AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=65 | grep output], [1], []) - - OVN_CLEANUP([hv1],[hv2]) -@@ -16276,7 +16271,7 @@ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=0 | grep in_port=1], [0], [ig - AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=65 | grep actions=output:1], [0], [ignore]) - - check ovn-nbctl --wait=hv lsp-set-options lsp0 requested-chassis=non-existant-chassis --OVS_WAIT_UNTIL([test 1 -le $(grep -c "Releasing lport lsp0 from this chassis" hv1/ovn-controller.log)]) -+OVS_WAIT_UNTIL([test 1 -le $(grep -c "Releasing lport lsp0" hv1/ovn-controller.log)]) - check ovn-nbctl --wait=hv sync - wait_column '' Port_Binding chasssi logical_port=lsp0 - AT_CHECK([as hv1 ovs-ofctl dump-flows br-int table=0 | grep in_port=1], [1], []) -@@ -18989,55 +18984,8 @@ for sf in 0 1; do - done - done - --# Test allow rule --#---------------- --ovn-nbctl acl-del lsw0 --# drop all packets to 11 and 21. --ovn-nbctl acl-add lsw0 to-lport 5000 'outport == @pg1 && eth.src == $set1' drop --# allow 0x1234 between 11 and 21 --check ovn-nbctl --wait=hv --log --severity=info --name=allow-acl acl-add lsw0 to-lport 6000 'outport == @pg1 && eth.src == $set1 && eth.type == 0x1234' allow --for sf in 0 1; do -- if test ${sf} = 1; then -- # Add a stateful rule and re-run the check to make sure the -- # allow rule is still effective.. -- check ovn-nbctl --wait=hv acl-add lsw0 from-lport 2000 'inport == "lp31" && ip' allow-related -- fi -- # dump information and flows with counters -- ovn-sbctl dump-flows -- list multicast_group > sbflows$sf -- AT_CAPTURE_FILE([sbflows0]) -- AT_CAPTURE_FILE([sbflows1]) -- for is in 1 2 3; do -- s=${is}1 -- for id in 1 2 3; do -- d=${id}1 -- -- if test $d != $s; -- then -- test_packet $s f000000000$d f000000000$s 1234 $d # allow 1234 to 11, 21, and 31 -- fi -- done -- -- # Broadcast and multicast. Allow from one to the other 2. -- if test ${is} = 1; then -- bcast="21 31" -- elif test ${is} = 2; then -- bcast="11 31" -- else -- bcast="11 21" -- fi -- test_packet $s ffffffffffff f000000000$s 1234 $bcast -- test_packet $s 010000000000 f000000000$s 1234 $bcast -- done --done -- --as hv1 ovs-ofctl -O OpenFlow13 dump-flows br-int > offlows1 --as hv2 ovs-ofctl -O OpenFlow13 dump-flows br-int > offlows2 --as hv3 ovs-ofctl -O OpenFlow13 dump-flows br-int > offlows3 -- --# Now check the packets actually received against the ones expected. --AT_CAPTURE_FILE([expected]) --AT_CAPTURE_FILE([received]) - check_packets() { -+ n_allowed=$1 - > expected - > received - for i in 1 2 3; do -@@ -19057,8 +19005,8 @@ check_packets() { - --- acl logging - hv1_drop hit 6 - hv2_drop hit 6 --hv1_allow hit 6 --hv2_allow hit 6 -+hv1_allow hit $n_allowed -+hv2_allow hit $n_allowed - EOF - - cat >>received </dev/null - } --OVS_WAIT_UNTIL([check_packets], [$at_diff -F'^---' expected received]) -+ -+# We need to wait and check here that packets are received as they should as otherwise packets -+# which were just sent might by handled after setting next ACL (allow) rules. -+OVS_WAIT_UNTIL([check_packets 0], [$at_diff -F'^---' expected received]) -+ -+# Test allow rule -+#---------------- -+ovn-nbctl acl-del lsw0 -+# drop all packets to 11 and 21. -+ovn-nbctl acl-add lsw0 to-lport 5000 'outport == @pg1 && eth.src == $set1' drop -+# allow 0x1234 between 11 and 21 -+check ovn-nbctl --wait=hv --log --severity=info --name=allow-acl acl-add lsw0 to-lport 6000 'outport == @pg1 && eth.src == $set1 && eth.type == 0x1234' allow -+for sf in 0 1; do -+ if test ${sf} = 1; then -+ # Add a stateful rule and re-run the check to make sure the -+ # allow rule is still effective.. -+ check ovn-nbctl --wait=hv acl-add lsw0 from-lport 2000 'inport == "lp31" && ip' allow-related -+ fi -+ # dump information and flows with counters -+ ovn-sbctl dump-flows -- list multicast_group > sbflows$sf -+ AT_CAPTURE_FILE([sbflows0]) -+ AT_CAPTURE_FILE([sbflows1]) -+ for is in 1 2 3; do -+ s=${is}1 -+ for id in 1 2 3; do -+ d=${id}1 -+ -+ if test $d != $s; -+ then -+ test_packet $s f000000000$d f000000000$s 1234 $d # allow 1234 to 11, 21, and 31 -+ fi -+ done -+ -+ # Broadcast and multicast. Allow from one to the other 2. -+ if test ${is} = 1; then -+ bcast="21 31" -+ elif test ${is} = 2; then -+ bcast="11 31" -+ else -+ bcast="11 21" -+ fi -+ test_packet $s ffffffffffff f000000000$s 1234 $bcast -+ test_packet $s 010000000000 f000000000$s 1234 $bcast -+ done -+done -+ -+as hv1 ovs-ofctl -O OpenFlow13 dump-flows br-int > offlows1 -+as hv2 ovs-ofctl -O OpenFlow13 dump-flows br-int > offlows2 -+as hv3 ovs-ofctl -O OpenFlow13 dump-flows br-int > offlows3 -+ -+# Now check the packets actually received against the ones expected. -+AT_CAPTURE_FILE([expected]) -+AT_CAPTURE_FILE([received]) -+OVS_WAIT_UNTIL([check_packets 6], [$at_diff -F'^---' expected received]) - - OVN_CLEANUP([hv1],[hv2],[hv3]) - -@@ -19790,11 +19791,6 @@ test_dhcp() { - as hv1 ovs-appctl netdev-dummy/receive hv${inport}-ext${inport} $request - } - -- --trim_zeros() { -- sed 's/\(00\)\{1,\}$//' --} -- - # This shell function sends a DHCPv6 request packet - # test_dhcpv6 INPORT SRC_MAC SRC_LLA DHCPv6_MSG_TYPE OFFER_IP OUTPORT... - # The OUTPORTs (zero or more) list the VIFs on which the original DHCPv6 -@@ -19876,12 +19872,9 @@ OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor0_hv1.log | grep -c NXT_RESUME`]) - # NXT_RESUMEs should be 0 in hv2. - OVS_WAIT_UNTIL([test 0 = `cat ofctl_monitor0_hv2.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/ext1-tx.pcap > ext1_v4.packets --cat ext1_v4.expected | cut -c -48 > expout --AT_CHECK([cat ext1_v4.packets | cut -c -48], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/ext1-tx.pcap], [ext1_v4.expected], ["cut -c -48"]) - # Skipping the IPv4 checksum. --cat ext1_v4.expected | cut -c 53- > expout --AT_CHECK([cat ext1_v4.packets | cut -c 53-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/ext1-tx.pcap], [ext1_v4.expected], ["cut -c 53-"]) - - # ovs-ofctl also resumes the packets and this causes other ports to receive - # the DHCP request packet. So reset the pcap files so that its easier to test. -@@ -19903,13 +19896,9 @@ OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor0_hv1.log | grep -c NXT_RESUME`]) - # NXT_RESUMEs should be 0 in hv2. - OVS_WAIT_UNTIL([test 0 = `cat ofctl_monitor0_hv2.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/ext1-tx.pcap | \ --sort > ext1_v6.packets --cat ext1_v6.expected | cut -c -120 > expout --AT_CHECK([cat ext1_v6.packets | cut -c -120], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/ext1-tx.pcap], [ext1_v6.expected], ["cut -c -120"]) - # Skipping the UDP checksum --cat ext1_v6.expected | cut -c 125- > expout --AT_CHECK([cat ext1_v6.packets | cut -c 125-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/ext1-tx.pcap], [ext1_v6.expected], ["cut -c 125-"]) - - rm -f ext1_v6.expected - rm -f ext1_v6.packets -@@ -19969,12 +19958,9 @@ OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor0_hv1.log | grep -c NXT_RESUME`]) - # NXT_RESUMEs should be 1 in hv2. - OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor0_hv2.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/ext1-tx.pcap > ext1_v4.packets --cat ext1_v4.expected | cut -c -48 > expout --AT_CHECK([cat ext1_v4.packets | cut -c -48], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/ext1-tx.pcap], [ext1_v4.expected], ["cut -c -48"]) - # Skipping the IPv4 checksum. --cat ext1_v4.expected | cut -c 53- > expout --AT_CHECK([cat ext1_v4.packets | cut -c 53-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/ext1-tx.pcap], [ext1_v4.expected], ["cut -c 53-"]) - - # ovs-ofctl also resumes the packets and this causes other ports to receive - # the DHCP request packet. So reset the pcap files so that its easier to test. -@@ -19995,13 +19981,9 @@ OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor0_hv1.log | grep -c NXT_RESUME`]) - # NXT_RESUMEs should be 2 in hv2. - OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor0_hv2.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/ext1-tx.pcap | \ --sort > ext1_v6.packets --cat ext1_v6.expected | cut -c -120 > expout --AT_CHECK([cat ext1_v6.packets | cut -c -120], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/ext1-tx.pcap], [ext1_v6.expected], ["cut -c -120"]) - # Skipping the UDP checksum --cat ext1_v6.expected | cut -c 125- > expout --AT_CHECK([cat ext1_v6.packets | cut -c 125-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/ext1-tx.pcap], [ext1_v6.expected], ["cut -c 125-"]) - - rm -f ext1_v6.expected - rm -f ext1_v6.packets -@@ -20077,12 +20059,9 @@ OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor0_hv1.log | grep -c NXT_RESUME`]) - # NXT_RESUMEs should be 2 in hv2. - OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor0_hv2.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/ext1-tx.pcap > ext1_v4.packets --cat ext1_v4.expected | cut -c -48 > expout --AT_CHECK([cat ext1_v4.packets | cut -c -48], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/ext1-tx.pcap], [ext1_v4.expected], ["cut -c -48"]) - # Skipping the IPv4 checksum. --cat ext1_v4.expected | cut -c 53- > expout --AT_CHECK([cat ext1_v4.packets | cut -c 53-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/ext1-tx.pcap], [ext1_v4.expected], ["cut -c 53-"]) - - # ovs-ofctl also resumes the packets and this causes other ports to receive - # the DHCP request packet. So reset the pcap files so that its easier to test. -@@ -20104,13 +20083,9 @@ OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor0_hv1.log | grep -c NXT_RESUME`]) - # NXT_RESUMEs should be 2 in hv2. - OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor0_hv2.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/ext1-tx.pcap | \ --sort > ext1_v6.packets --cat ext1_v6.expected | cut -c -120 > expout --AT_CHECK([cat ext1_v6.packets | cut -c -120], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/ext1-tx.pcap], [ext1_v6.expected], ["cut -c -120"]) - # Skipping the UDP checksum --cat ext1_v6.expected | cut -c 125- > expout --AT_CHECK([cat ext1_v6.packets | cut -c 125-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/ext1-tx.pcap], [ext1_v6.expected], ["cut -c 125-"]) - - rm -f ext1_v6.expected - rm -f ext1_v6.packets -@@ -20158,12 +20133,9 @@ OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor0_hv2.log | grep -c NXT_RESUME`]) - # NXT_RESUMEs should be 1 in hv3. - OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor0_hv3.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/ext1-tx.pcap > ext1_v4.packets --cat ext1_v4.expected | cut -c -48 > expout --AT_CHECK([cat ext1_v4.packets | cut -c -48], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/ext1-tx.pcap], [ext1_v4.expected], ["cut -c -48"]) - # Skipping the IPv4 checksum. --cat ext1_v4.expected | cut -c 53- > expout --AT_CHECK([cat ext1_v4.packets | cut -c 53-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/ext1-tx.pcap], [ext1_v4.expected], ["cut -c 53-"]) - - # ovs-ofctl also resumes the packets and this causes other ports to receive - # the DHCP request packet. So reset the pcap files so that its easier to test. -@@ -20188,13 +20160,9 @@ OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor0_hv2.log | grep -c NXT_RESUME`]) - # NXT_RESUMEs should be 2 in hv3. - OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor0_hv3.log | grep -c NXT_RESUME`]) - --$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/ext1-tx.pcap | \ --sort > ext1_v6.packets --cat ext1_v6.expected | cut -c -120 > expout --AT_CHECK([cat ext1_v6.packets | cut -c -120], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/ext1-tx.pcap], [ext1_v6.expected], ["cut -c -120"]) - # Skipping the UDP checksum --cat ext1_v6.expected | cut -c 125- > expout --AT_CHECK([cat ext1_v6.packets | cut -c 125-], [0], [expout]) -+OVN_CHECK_PACKETS([hv1/ext1-tx.pcap], [ext1_v6.expected], ["cut -c 125-"]) - - # disconnect hv3 from the network, hv1 should take over - as hv3 -@@ -21223,6 +21191,7 @@ OVN_FOR_EACH_NORTHD([ - AT_SETUP([ipam to non-ipam]) - ovn_start - -+check ovn-nbctl --wait=sb sync - ovn-nbctl --wait=hv set NB_Global . options:mac_prefix="0a:00:00:00:00:00" - ovn-nbctl ls-add sw0 - ovn-nbctl lsp-add sw0 p0 -- lsp-set-addresses p0 dynamic -@@ -23426,7 +23395,7 @@ check ovn-nbctl set Logical_Switch sw2 \ - other_config:mcast_querier="false" - - # Enable multicast snooping on sw3. --check ovn-nbctl --wait=sb set Logical_Switch sw3 \ -+check ovn-nbctl --wait=hv set Logical_Switch sw3 \ - other_config:mcast_querier="false" \ - other_config:mcast_snoop="true" - -@@ -23465,7 +23434,7 @@ OVS_WAIT_UNTIL( - [$at_diff -F'^---' exp rcv]) - - # Enable multicast relay on rtr --check ovn-nbctl --wait=sb set logical_router rtr options:mcast_relay="true" -+check ovn-nbctl --wait=hv set logical_router rtr options:mcast_relay="true" - - AT_CAPTURE_FILE([sbflows6]) - ovn-sbctl dump-flows > sbflows6 -@@ -26413,10 +26382,13 @@ check ovn-nbctl lsp-add ts ts-lr3 \ - wait_for_ports_up - - ovn_as az1 -+OVS_WAIT_UNTIL([ovn-nbctl show | grep ts-lr2]) - check ovn-nbctl lsp-set-options ts-lr2 requested-chassis=hv2 -+OVS_WAIT_UNTIL([ovn-nbctl show | grep ts-lr3]) - check ovn-nbctl lsp-set-options ts-lr3 requested-chassis=hv2 - - ovn_as az2 -+OVS_WAIT_UNTIL([ovn-nbctl show | grep ts-lr1]) - check ovn-nbctl lsp-set-options ts-lr1 requested-chassis=hv1 - - dnl Enable unregistered IP multicast flooding and IP multicast relay. -@@ -26625,10 +26597,13 @@ check ovn-nbctl lsp-add ts ts-lr3 \ - wait_for_ports_up - - ovn_as az1 -+OVS_WAIT_UNTIL([ovn-nbctl show | grep ts-lr2]) - check ovn-nbctl lsp-set-options ts-lr2 requested-chassis=hv2 -+OVS_WAIT_UNTIL([ovn-nbctl show | grep ts-lr3]) - check ovn-nbctl lsp-set-options ts-lr3 requested-chassis=hv2 - - ovn_as az2 -+OVS_WAIT_UNTIL([ovn-nbctl show | grep ts-lr1]) - check ovn-nbctl lsp-set-options ts-lr1 requested-chassis=hv1 - - dnl Enable IP multicast snooping and IP multicast relay. Reports are -@@ -27984,8 +27959,9 @@ ovn-nbctl ls-add ls1 - ovn-nbctl --wait=sb lsp-add ls1 lsp1 - - # Simulate the fact that lsp1 had been previously bound on hv1. --ovn-sbctl --id=@e create encap chassis_name=hv1 ip="192.168.0.1" type="geneve" \ -- -- --id=@c create chassis name=hv1 encaps=@e \ -+ovn-sbctl --id=@e1 create encap chassis_name=hv1 ip="192.168.0.1" type="geneve" \ -+ --id=@e2 create encap chassis_name=hv1 ip="192.168.0.1" type="vxlan" \ -+ -- --id=@c create chassis name=hv1 encaps=@e1,@e2 \ - -- set Port_Binding lsp1 chassis=@c - - as hv1 -@@ -28011,8 +27987,9 @@ ovn-nbctl ls-add ls1 - ovn-nbctl --wait=sb lsp-add ls1 lsp1 - - # Simulate the fact that lsp1 had been previously bound on hv1. --ovn-sbctl --id=@e create encap chassis_name=hv1 ip="192.168.0.1" type="geneve" \ -- -- --id=@c create chassis hostname=hv1 name=hv1 encaps=@e \ -+ovn-sbctl --id=@e1 create encap chassis_name=hv1 ip="192.168.0.1" type="geneve" \ -+ --id=@e2 create encap chassis_name=hv1 ip="192.168.0.1" type="vxlan" \ -+ -- --id=@c create chassis name=hv1 encaps=@e1,@e2 \ - -- set Port_Binding lsp1 chassis=@c - - as hv1 -@@ -28137,9 +28114,10 @@ OVS_WAIT_UNTIL([ - ]) - - as hv1 check ovs-ofctl del-flows br-phys -+ - AT_DATA([flows.txt], [dnl --table=0, priority=0 actions=NORMAL - table=0, priority=200 arp,actions=drop -+table=0, priority=0 actions=NORMAL - table=0, priority=100, pkt_mark=0x64 actions=drop - table=0, priority=100, pkt_mark=0x2 actions=drop - table=0, priority=100, pkt_mark=0x3 actions=drop -@@ -28966,7 +28944,7 @@ AT_CHECK([ - grep "priority=200" | \ - grep -c "move:NXM_NX_CT_LABEL\\[[\\]]->NXM_NX_XXREG1\\[[\\]],move:NXM_NX_XXREG1\\[[32..79\\]]->NXM_OF_ETH_DST" - done; :], [0], [dnl --6 -+2 - 1 - 0 - 0 -@@ -29091,7 +29069,7 @@ AT_CHECK([ - grep "priority=200" | \ - grep -c "move:NXM_NX_CT_LABEL\\[[\\]]->NXM_NX_XXREG1\\[[\\]],move:NXM_NX_XXREG1\\[[32..79\\]]->NXM_OF_ETH_DST" - done; :], [0], [dnl --6 -+2 - 1 - 0 - 0 -@@ -30785,7 +30763,6 @@ check ovn-nbctl --wait=hv ls-lb-del sw0 lb-ipv6 - # original destination tuple. - # - # ovn-controller should fall back to matching on ct_nw_dst()/ct_tp_dst(). --as northd-backup ovn-appctl -t NORTHD_TYPE pause - as northd ovn-appctl -t NORTHD_TYPE pause - - check ovn-sbctl \ -@@ -30836,7 +30813,6 @@ OVS_WAIT_FOR_OUTPUT([as hv2 ovs-ofctl dump-flows br-int table=70 | ofctl_strip_a - - # Resume ovn-northd. - as northd ovn-appctl -t NORTHD_TYPE resume --as northd-backup ovn-appctl -t NORTHD_TYPE resume - check ovn-nbctl --wait=hv sync - - as hv2 ovs-vsctl del-port hv2-vif1 -@@ -30957,9 +30933,6 @@ AT_CHECK([grep -c $northd_version hv1/ovn-controller.log], [0], [1 - as northd - OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE]) - --as northd-backup --OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE]) -- - check ovn-sbctl set SB_Global . options:northd_internal_version=foo - - as hv1 -@@ -31101,7 +31074,6 @@ AS_BOX([ovn-controller should not reset Port_Binding.up without northd]) - # Pause northd and clear the "up" field to simulate older ovn-northd - # versions writing to the Southbound DB. - as northd ovn-appctl -t NORTHD_TYPE pause --as northd-backup ovn-appctl -t NORTHD_TYPE pause - - as hv1 ovn-appctl -t ovn-controller debug/pause - check ovn-sbctl clear Port_Binding lsp1 up -@@ -31117,7 +31089,6 @@ check_column "" Port_Binding up logical_port=lsp1 - # Once northd should explicitly set the Port_Binding.up field to 'false' and - # ovn-controller sets it to 'true' as soon as the update is processed. - as northd ovn-appctl -t NORTHD_TYPE resume --as northd-backup ovn-appctl -t NORTHD_TYPE resume - wait_column "true" Port_Binding up logical_port=lsp1 - wait_column "true" nb:Logical_Switch_Port up name=lsp1 - -@@ -31272,7 +31243,6 @@ check ovn-nbctl lsp-set-addresses sw0-p4 "00:00:00:00:00:04 192.168.47.4" - # will be sent in one transaction. - - check as northd ovn-appctl -t NORTHD_TYPE pause --check as northd-backup ovn-appctl -t NORTHD_TYPE pause - - check ovn-nbctl lsp-add sw0 sw0-p1 - check ovn-nbctl lsp-set-addresses sw0-p1 "00:00:00:00:00:01 192.168.47.1" -@@ -31453,10 +31423,6 @@ send_icmp_packet() { - as hv$hv ovs-appctl netdev-dummy/receive hv$hv-vif$inport $packet - } - --trim_zeros() { -- sed 's/\(00\)\{1,\}$//' --} -- - AS_BOX([Wait for all ports to be up]) - wait_for_ports_up - -@@ -33727,7 +33693,6 @@ check as hv1 ovn-appctl -t ovn-controller exit - - # Pause northd to guarantee that ovn-controller starts before requested_chassis - # column is filled. --check as northd-backup ovn-appctl -t ovn-northd pause - check as northd ovn-appctl -t ovn-northd pause - - # Wait until requested_chassis is empty -@@ -33741,7 +33706,6 @@ wait_column "hv1" Chassis name - - # Start northd and wait for events to be processed - check as northd ovn-appctl -t ovn-northd resume --check as northd-backup ovn-appctl -t ovn-northd resume - - wait_for_ports_up lsp1 - -@@ -34471,7 +34435,7 @@ dnat_zone=$(ovs-ofctl dump-flows br-int table=$DNAT_TABLE,metadata=0x${lr0_dp_ke - if test -n "$dnat_zone"; then - dnat_zone=${dnat_zone::-1} - fi --snat_zone=$(ovs-ofctl dump-flows br-int table=$SNAT_TABLE,metadata=0x${lr0_dp_key} | grep priority=153 | grep -o zone=.*, | cut -d '=' -f 2) -+snat_zone=$(ovs-ofctl dump-flows br-int table=$SNAT_TABLE,metadata=0x${lr0_dp_key} | grep priority=153 | grep ct_state=-trk | grep -o zone=.*, | cut -d '=' -f 2) - if test -n "$snat_zone"; then - snat_zone=${snat_zone::-1} - fi -@@ -34488,7 +34452,7 @@ dnat_zone=$(ovs-ofctl dump-flows br-int table=$DNAT_TABLE,metadata=0x${lr0_dp_ke - if test -n "$dnat_zone"; then - dnat_zone=${dnat_zone::-1} - fi --snat_zone=$(ovs-ofctl dump-flows br-int table=$SNAT_TABLE,metadata=0x${lr0_dp_key} | grep priority=153 | grep -o zone=.*, | cut -d '=' -f 2) -+snat_zone=$(ovs-ofctl dump-flows br-int table=$SNAT_TABLE,metadata=0x${lr0_dp_key} | grep priority=153 | grep ct_state=-trk | grep -o zone=.*, | cut -d '=' -f 2) - if test -n "$snat_zone"; then - snat_zone=${snat_zone::-1} - fi -@@ -34572,6 +34536,7 @@ AT_CLEANUP - - OVN_FOR_EACH_NORTHD([ - AT_SETUP([MAC binding aging]) -+AT_SKIP_IF([test $HAVE_SCAPY = no]) - ovn_start - - net_add n1 -@@ -34748,8 +34713,8 @@ check ovn-nbctl lsp-add sw0 sw0-p1 - check ovn-nbctl lsp-add sw0 lsp - check ovn-nbctl lsp-set-type lsp router - check ovn-nbctl lsp-set-options lsp router-port=lrp --check ovn-nbctl lsp-set-addresses lsp 00:00:00:00:00:1 --check ovn-nbctl lrp-add ro0 lrp 00:00:00:00:00:1 aef0:0:0:0:0:0:0:1/64 -+check ovn-nbctl lsp-set-addresses lsp 00:00:00:00:00:01 -+check ovn-nbctl lrp-add ro0 lrp 00:00:00:00:00:01 aef0:0:0:0:0:0:0:1/64 - check ovn-nbctl set Logical_Router_Port lrp ipv6_ra_configs:send_periodic=true \ - -- set Logical_Router_Port lrp ipv6_ra_configs:address_mode=slaac \ - -- set Logical_Router_Port lrp ipv6_ra_configs:mtu=1280 \ -@@ -34843,8 +34808,8 @@ check ovn-nbctl lsp-add sw0 sw0-p1 - check ovn-nbctl lsp-add sw0 lsp - check ovn-nbctl lsp-set-type lsp router - check ovn-nbctl lsp-set-options lsp router-port=lrp --check ovn-nbctl lsp-set-addresses lsp 00:00:00:00:00:1 --check ovn-nbctl --wait=hv lrp-add ro0 lrp 00:00:00:00:00:1 aef0:0:0:0:0:0:0:1/64 -+check ovn-nbctl lsp-set-addresses lsp 00:00:00:00:00:01 -+check ovn-nbctl --wait=hv lrp-add ro0 lrp 00:00:00:00:00:01 aef0:0:0:0:0:0:0:1/64 - check ovn-nbctl --wait=hv lsp-del lsp - check ovn-nbctl lrp-del lrp - check ovn-nbctl --wait=hv sync -@@ -35389,37 +35354,6 @@ OVN_CLEANUP([hv1],[hv2]) - AT_CLEANUP - ]) - --OVN_FOR_EACH_NORTHD([ --AT_SETUP([feature inactivity probe]) --ovn_start --net_add n1 -- --sim_add hv1 --as hv1 --check ovs-vsctl add-br br-phys --ovn_attach n1 br-phys 192.168.0.1 -- --dnl Ensure that there are 4 openflow connections. --OVS_WAIT_UNTIL([test "$(grep -c 'negotiated OpenFlow version' hv1/ovs-vswitchd.log)" -eq "4"]) -- --dnl "Wait" 3 times 60 seconds and ensure ovn-controller writes to the --dnl openflow connections in the meantime. This should allow ovs-vswitchd --dnl to probe the openflow connections at least twice. -- --as hv1 ovs-appctl time/warp 60000 --check ovn-nbctl --wait=hv sync -- --as hv1 ovs-appctl time/warp 60000 --check ovn-nbctl --wait=hv sync -- --as hv1 ovs-appctl time/warp 60000 --check ovn-nbctl --wait=hv sync -- --AT_CHECK([test -z "`grep disconnecting hv1/ovs-vswitchd.log`"]) --OVN_CLEANUP([hv1]) --AT_CLEANUP --]) -- - OVN_FOR_EACH_NORTHD([ - AT_SETUP([Logical flows with Chassis_Template_Var references]) - AT_KEYWORDS([templates]) -@@ -35795,7 +35729,7 @@ as hv1 ovs-vsctl set-ssl \ - echo hv3 > ${OVN_SYSCONFDIR}/test_hv - - # the last argument is passed to ovn-controller through cli --ovn_attach n1 br-phys 192.168.0.1 24 vxlan hv1 -n hv3 -+ovn_attach n1 br-phys 192.168.0.1 24 vxlan hv1 hv3 - - sim_add hv2 - as hv2 -@@ -36728,7 +36662,6 @@ check ovn-nbctl lsp-add ls2 public2 - check ovn-nbctl lsp-set-addresses public2 unknown - check ovn-nbctl lsp-set-type public2 localnet - check ovn-nbctl --wait=sb set Logical_Switch_Port public2 options:qos_min_rate=6000000000 options:qos_max_rate=7000000000 options:qos_burst=8000000000 options:network_name=phys --check ovn-nbctl --wait=sb lsp-set-options public2 qos_min_rate=6000000000 qos_max_rate=7000000000 qos_burst=8000000000 - - # Let's now send ovn controller to sleep, so it will receive both ofport notification and ls deletion simultaneously - sleep_controller hv-1 -@@ -36861,14 +36794,14 @@ check ovn-nbctl ls-add sw0 - check ovn-nbctl lsp-add sw0 sw0-port1 - check ovn-nbctl lsp-set-addresses sw0-port1 "50:54:00:00:00:01 192.168.0.2" - -+ovs-vsctl add-port br-int p1 -- \ -+ set Interface p1 external_ids:iface-id=sw0-port1 -+ - check ovn-nbctl lsp-add sw0 sw0-lr0 - check ovn-nbctl lsp-set-type sw0-lr0 router - check ovn-nbctl lsp-set-addresses sw0-lr0 00:00:00:00:ff:01 - check ovn-nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0 - --ovs-vsctl add-port br-int p1 -- \ -- set Interface p1 external_ids:iface-id=sw0-port1 -- - check ovn-appctl -t ovn-controller vlog/set dbg:main - - wait_for_ports_up -@@ -37005,3 +36938,730 @@ AT_CHECK([grep -c "NXT_CT_FLUSH_ZONE" hv1/ovs-vswitchd.log], [0], [dnl - OVN_CLEANUP([hv1]) - AT_CLEANUP - ]) -+ -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([virtual port claim race condition]) -+AT_KEYWORDS([virtual ports]) -+ovn_start -+ -+send_garp() { -+ local hv=$1 inport=$2 eth_src=$3 eth_dst=$4 spa=$5 tpa=$6 -+ local request=${eth_dst}${eth_src}08060001080006040001${eth_src}${spa}${eth_dst}${tpa} -+ as hv$hv ovs-appctl netdev-dummy/receive hv${hv}-vif$inport $request -+} -+ -+net_add n1 -+ -+sim_add hv1 -+as hv1 -+ovs-vsctl add-br br-phys -+ovn_attach n1 br-phys 192.168.0.1 -+ovn-appctl vlog/set dbg -+ovs-vsctl -- add-port br-int hv1-vif1 -- \ -+ set interface hv1-vif1 external-ids:iface-id=sw0-p1 \ -+ options:tx_pcap=hv1/vif1-tx.pcap \ -+ options:rxq_pcap=hv1/vif1-rx.pcap \ -+ ofport-request=1 -+ovs-vsctl -- add-port br-int hv1-vif3 -- \ -+ set interface hv1-vif3 \ -+ options:tx_pcap=hv1/vif3-tx.pcap \ -+ options:rxq_pcap=hv1/vif3-rx.pcap \ -+ ofport-request=3 -+ -+ovs-appctl -t ovn-controller vlog/set dbg -+ -+ovn-nbctl ls-add sw0 -+ -+check ovn-nbctl lsp-add sw0 sw0-vir -+check ovn-nbctl lsp-set-addresses sw0-vir "50:54:00:00:00:10 10.0.0.10" -+check ovn-nbctl lsp-set-port-security sw0-vir "50:54:00:00:00:10 10.0.0.10" -+check ovn-nbctl lsp-set-type sw0-vir virtual -+check ovn-nbctl set logical_switch_port sw0-vir options:virtual-ip=10.0.0.10 -+check ovn-nbctl set logical_switch_port sw0-vir options:virtual-parents=sw0-p1 -+ -+check ovn-nbctl lsp-add sw0 sw0-p1 -+check ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03 10.0.0.3 1000::3" -+check ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03 10.0.0.3 10.0.0.10 1000::3" -+ -+# Create a logical router and attach both logical switches -+check ovn-nbctl lr-add lr0 -+check ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:ff:01 10.0.0.1/24 1000::a/64 -+check ovn-nbctl lsp-add sw0 sw0-lr0 -+check ovn-nbctl lsp-set-type sw0-lr0 router -+check ovn-nbctl lsp-set-addresses sw0-lr0 00:00:00:00:ff:01 -+check ovn-nbctl lsp-set-options sw0-lr0 router-port=lr0-sw0 -+ -+wait_for_ports_up -+ovn-nbctl --wait=hv sync -+hv1_ch_uuid=`ovn-sbctl --bare --columns _uuid find chassis name="hv1"` -+ -+# Try to bind sw0-vir directly to an OVS port. This should be ignored by -+# ovn-controller. -+as hv1 ovs-vsctl set interface hv1-vif3 external-ids:iface-id=sw0-vir -+ -+# Make sb to sleep, so that claim of sw0-vir (through pinctrl) and hv1-vif3 can be handled within same idl by controller -+sleep_sb -+ -+# From sw0-p0 send GARP for 10.0.0.10. hv1 should claim sw0-vir -+# and sw0-p1 should be its virtual_parent. -+eth_src=505400000003 -+eth_dst=ffffffffffff -+spa=$(ip_to_hex 10 0 0 10) -+tpa=$(ip_to_hex 10 0 0 10) -+send_garp 1 1 $eth_src $eth_dst $spa $tpa -+ -+OVS_WAIT_UNTIL([test 1 = `cat hv1/ovn-controller.log | grep "pinctrl received packet-in" | \ -+grep opcode=BIND_VPORT | grep OF_Table_ID=29 | wc -l`]) -+ -+sleep_controller hv1 -+ -+# Cleanup hv1-vif3. This should not interfere with sw0-vir claim -+as hv1 ovs-vsctl del-port hv1-vif3 -+ -+wake_up_sb -+ovn-nbctl --wait=sb sync -+wake_up_controller hv1 -+check ovn-nbctl --wait=hv sync -+ -+wait_row_count Port_Binding 1 logical_port=sw0-vir chassis=$hv1_ch_uuid -+check_row_count Port_Binding 1 logical_port=sw0-vir virtual_parent=sw0-p1 -+wait_for_ports_up sw0-vir -+check ovn-nbctl --wait=hv sync -+ -+OVN_CLEANUP([hv1]) -+AT_CLEANUP -+]) -+ -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([pod to pod with localnet_learn_fdb]) -+AT_SKIP_IF([test $HAVE_SCAPY = no]) -+ -+# 6 VIFs, 3 per HV: vif11, vif12, vif13 on hv1. -+# vif11 will exchange packets with vif21, vif12 w/ vif22 and so on. -+# -+ovn_start -+net_add n1 -+ -+check ovn-nbctl ls-add ls0 -+ -+check ovn-nbctl lsp-add ls0 ln_port -- \ -+ lsp-set-addresses ln_port unknown -- \ -+ lsp-set-type ln_port localnet -- \ -+ lsp-set-options ln_port network_name=physnet1 -+ -+for i in $(seq 1 3); do -+ check ovn-nbctl lsp-add ls0 vif1$i -- \ -+ lsp-set-addresses vif1$i unknown -+ check ovn-nbctl lsp-add ls0 vif2$i -- \ -+ lsp-set-addresses vif2$i unknown -+done -+ -+n_pkt=(0 0 0 0 0 0) -+ -+for hv in 1 2; do -+ sim_add hv${hv} -+ as hv${hv} -+ ovs-vsctl add-br br-phys -+ ovn_attach n1 br-phys 192.168.0.${hv} -+ -+ for i in $(seq 1 3); do -+ ovs-vsctl -- add-port br-int vif${hv}${i} -- \ -+ set interface vif${hv}${i} external-ids:iface-id=vif${hv}${i} \ -+ options:tx_pcap=hv${hv}/vif${hv}${i}-tx.pcap \ -+ options:rxq_pcap=hv${hv}/vif${hv}${i}-rx.pcap \ -+ ofport-request=$i -+ done -+ ovs-vsctl -- add-port br-phys ext0 -- \ -+ set interface ext0 \ -+ options:tx_pcap=hv${hv}/ext0-tx.pcap \ -+ options:rxq_pcap=hv${hv}/ext0-rx.pcap \ -+ ofport-request=4 -+ ovs-vsctl set open . external_ids:ovn-bridge-mappings=physnet1:br-phys -+done -+ -+OVN_POPULATE_ARP -+wait_for_ports_up -+check ovn-nbctl --wait=hv sync -+ -+ln_port_key=$(fetch_column port_binding tunnel_key logical_port=ln_port) -+vif11_key=$(fetch_column port_binding tunnel_key logical_port=vif11) -+vif12_key=$(fetch_column port_binding tunnel_key logical_port=vif12) -+vif13_key=$(fetch_column port_binding tunnel_key logical_port=vif13) -+vif21_key=$(fetch_column port_binding tunnel_key logical_port=vif21) -+vif22_key=$(fetch_column port_binding tunnel_key logical_port=vif22) -+vif23_key=$(fetch_column port_binding tunnel_key logical_port=vif23) -+ -+ensure_controller_run() { -+# We want to make sure controller could run at least one full loop. -+# We can't use wait=hv as sb might be sleeping. -+# Use 2 ovn-appctl to guarentee that ovn-controller run the full loop, and not just the unixctl handling -+ hv=$1 -+ OVS_WAIT_UNTIL([test x$(as $hv ovn-appctl -t ovn-controller debug/status) = "xrunning"]) -+ OVS_WAIT_UNTIL([test x$(as $hv ovn-appctl -t ovn-controller debug/status) = "xrunning"]) -+} -+ -+wait_for_packets() { -+ local hv=$1 -+ local vif=$2 -+ counter=$(((${hv:2} - 1) * 3 + ${vif:4} - 1)) -+ n_pkt[[$counter]]=$((${n_pkt[[$counter]]} + 1)) -+ echo "waiting for ${n_pkt[[$counter]]} packets on ${hv}/${vif} using counter $counter" -+ OVS_WAIT_UNTIL([test $(tcpdump ip -nnner ${hv}/${vif}-tx.pcap | wc -l) -eq ${n_pkt[[$counter]]}]) -+} -+ -+check_no_packets() { -+ local hv=$1 -+ local vif=$2 -+ counter=$(((${hv:2} - 1) * 3 + ${vif:4} - 1)) -+ echo "waiting for ${n_pkt[[$counter]]} packets on ${hv}/${vif} using counter $counter" -+ OVS_WAIT_UNTIL([test $(tcpdump ip -nnner ${hv}/${vif}-tx.pcap | wc -l) -eq ${n_pkt[[$counter]]}]) -+} -+ -+send_packet() { -+ hv=$1 -+ a_src=$2 -+ a_dst=$3 -+ dev=vif$2 -+ AS_BOX([$(date +%H:%M:%S.%03N) sending packet from $dev in $hv $a_src to $a_dst]) -+ packet=$(fmt_pkt " -+ Ether(dst='00:00:00:00:10:${a_dst}', src='00:00:00:00:10:${a_src}') / -+ IP(src='192.168.10.${a_src}', dst='192.168.10.${a_dst}') / -+ UDP(sport=1234, dport=1235) -+ ") -+ as $hv ovs-appctl netdev-dummy/receive $dev $packet -+} -+ -+check_flow_count() { -+ hv=$1 -+ count=$2 -+ echo "Checking flow count for $hv is $count" -+ OVS_WAIT_UNTIL([test $count = $(as $hv ovs-ofctl dump-flows br-int table=72 | grep -v "NXST_FLOW reply" | wc -l)]) -+} -+ -+# Sending packet in both direction. Should create FDB entries for vifs -+# No localnet_learn_fdb yet -+AS_BOX([$(date +%H:%M:%S.%03N) vif11 <=> vif21]) -+send_packet hv1 11 21 -+for i in 1 2 3; do -+ wait_for_packets hv2 vif2${i} -+done -+for i in 2 3; do -+ wait_for_packets hv1 vif1${i} -+done -+# vif11 should now own the mac -+wait_column "$vif11_key" fdb port_key mac='"00:00:00:00:10:11"' -+ -+send_packet hv2 21 11 -+wait_for_packets hv1 vif11 -+for i in 2 3; do -+ check_no_packets hv1 vif1${i} -+done -+wait_column "$vif21_key" fdb port_key mac='"00:00:00:00:10:21"' -+ -+check_flow_count hv1 2 -+check_flow_count hv2 2 -+ -+# We now enable localnet_learn_fdb -+# We check how it behaves with existing vif entries in fdb -+check ovn-nbctl --wait=hv set logical_switch_port ln_port options:localnet_learn_fdb=true -+ -+AS_BOX([$(date +%H:%M:%S.%03N) vif11 <=> vif21 after learn_fdb]) -+send_packet hv1 11 21 -+ -+wait_for_packets hv2 vif21 -+for i in 2 3; do -+ check_no_packets hv2 vif2${i} -+done -+wait_column "$vif11_key" fdb port_key mac='"00:00:00:00:10:11"' -+ -+send_packet hv2 21 11 -+wait_for_packets hv1 vif11 -+for i in 2 3; do -+ check_no_packets hv1 vif1${i} -+done -+wait_column "$vif21_key" fdb port_key mac='"00:00:00:00:10:21"' -+ -+# In both controllers, -+# - 1st packet (in both dir) should have reached controller for the vif, not for localnet (as learn_fdb disabled for localnet) -+# - 2nd packet should not cause any upcall to controller as vif already owns the mac. -+AT_CHECK([test 1 = `cat hv1/ovs-vswitchd.log | grep NXT_PACKET_IN2 | wc -l`]) -+AT_CHECK([test 1 = `cat hv2/ovs-vswitchd.log | grep NXT_PACKET_IN2 | wc -l`]) -+ -+check_flow_count hv1 4 -+check_flow_count hv2 4 -+ -+# Send a few more packets -+send_packet hv1 11 21 -+send_packet hv2 21 11 -+ -+for hv in 1 2; do -+ wait_for_packets hv${hv} vif${hv}1 -+ for i in 2 3; do -+ echo CHECK -+ check_no_packets hv${hv} vif${hv}${i} -+ done -+done -+ -+# The last packets should have gone through the fast path -+AT_CHECK([test 1 = `cat hv1/ovs-vswitchd.log | grep NXT_PACKET_IN2 | wc -l`]) -+AT_CHECK([test 1 = `cat hv2/ovs-vswitchd.log | grep NXT_PACKET_IN2 | wc -l`]) -+ -+# Check that there are no bad surprises -+wait_column "$vif11_key" fdb port_key mac='"00:00:00:00:10:11"' -+wait_column "$vif21_key" fdb port_key mac='"00:00:00:00:10:21"' -+ -+# We will now create fdb entries AFTER enabing localnet_learn_fdb -+# We make ovn_controller (hv1 or hv2) to sleep to control who writes first to fdb -+# as otherwise no guarentee. -+AS_BOX([$(date +%H:%M:%S.%03N) vif12 <=> vif22]) -+# We make sure that the fdb update by the vif is done after the localnet update -+sleep_controller hv1 -+send_packet hv1 12 22 -+for i in 1 3; do -+ wait_for_packets hv1 vif1${i} -+done -+for i in 1 2 3; do -+ wait_for_packets hv2 vif2${i} -+done -+ -+# ln_port should own the mac as vif not written yet -+wait_column "$ln_port_key" fdb port_key mac='"00:00:00:00:10:12"' -+ -+wake_up_controller hv1 -+# vif1 should now own the mac -+wait_column "$vif12_key" fdb port_key mac='"00:00:00:00:10:12"' -+ -+sleep_controller hv2 -+send_packet hv2 22 12 -+wait_for_packets hv1 vif12 -+for i in 1 3; do -+ check_no_packets hv1 vif1${i} -+done -+wait_column "$ln_port_key" fdb port_key mac='"00:00:00:00:10:22"' -+ -+wake_up_controller hv2 -+wait_column "$vif22_key" fdb port_key mac='"00:00:00:00:10:22"' -+ -+check_flow_count hv1 8 -+check_flow_count hv2 8 -+ -+AS_BOX([$(date +%H:%M:%S.%03N) vif13 <=> vif23 ]) -+# Now we do the other way around: we make sure that the localnet update is done after the vif update. -+# So, when packet is sent from vif1 to vif2, vif1 will be learnt (by hv1) and written in sb -+# Then, when we wake up ovn-controller on hv2, it will learn on localnet. -+# This used to cause localnet entry to overwrite vif entry in sb -+sleep_controller hv2 -+send_packet hv1 13 23 -+for i in 1 2; do -+ wait_for_packets hv1 vif1${i} -+done -+for i in 1 2 3; do -+ wait_for_packets hv2 vif2${i} -+done -+ -+wait_column "$vif13_key" fdb port_key mac='"00:00:00:00:10:13"' -+ -+ -+# At this point, FDB contains vif1 entry for mac 00:00:00:00:10:13. -+# However, as hv2 controller is sleeping, the flows in hv2 do not -+# contain the flows related to that fdb entry. -+# Hence, the packet which went through still failed the lookup. -+wake_up_controller hv2 -+ -+# FDB shoud not have changed. Just make sure controller has run and check fdb -+ensure_controller_run hv2 -+wait_column "$vif13_key" fdb port_key mac='"00:00:00:00:10:13"' -+ -+sleep_controller hv1 -+send_packet hv2 23 13 -+wait_for_packets hv1 vif13 -+for i in 1 2; do -+ check_no_packets hv2 vif2${i} -+done -+for i in 1 2; do -+ check_no_packets hv1 vif1${i} -+done -+wait_column "$vif23_key" fdb port_key mac='"00:00:00:00:10:23"' -+ -+wake_up_controller hv1 -+ensure_controller_run hv1 -+wait_column "$vif23_key" fdb port_key mac='"00:00:00:00:10:23"' -+ -+# In both controllers -+# - vif11 <=> vif21: 1 PACKET_IN -+# - vif12 <=> vif22: 2 PACKET_IN -+# - vif13 <=> vif23: 2 PACKET_IN -+# controller + . -+AT_CHECK([test 5 = `cat hv1/ovs-vswitchd.log | grep NXT_PACKET_IN2 | wc -l`]) -+AT_CHECK([test 5 = `cat hv2/ovs-vswitchd.log | grep NXT_PACKET_IN2 | wc -l`]) -+ -+# Send a few more packets -+send_packet hv1 13 23 -+send_packet hv2 23 13 -+wait_for_packets hv2 vif23 -+wait_for_packets hv1 vif13 -+for i in 1 2; do -+ check_no_packets hv1 vif1${i} -+ check_no_packets hv2 vif2${i} -+done -+send_packet hv1 13 23 -+send_packet hv2 23 13 -+wait_for_packets hv2 vif23 -+wait_for_packets hv1 vif13 -+for i in 1 2; do -+ check_no_packets hv1 vif1${i} -+ check_no_packets hv2 vif2${i} -+done -+ -+# The last packets should have gone through the fast path -+AT_CHECK([test 5 = `cat hv1/ovs-vswitchd.log | grep NXT_PACKET_IN2 | wc -l`]) -+AT_CHECK([test 5 = `cat hv2/ovs-vswitchd.log | grep NXT_PACKET_IN2 | wc -l`]) -+ -+# Check that there are no bad surprises -+wait_column "$vif11_key" fdb port_key mac='"00:00:00:00:10:11"' -+wait_column "$vif12_key" fdb port_key mac='"00:00:00:00:10:12"' -+wait_column "$vif13_key" fdb port_key mac='"00:00:00:00:10:13"' -+wait_column "$vif21_key" fdb port_key mac='"00:00:00:00:10:21"' -+wait_column "$vif22_key" fdb port_key mac='"00:00:00:00:10:22"' -+wait_column "$vif23_key" fdb port_key mac='"00:00:00:00:10:23"' -+ -+check_flow_count hv1 12 -+check_flow_count hv2 12 -+ -+OVN_CLEANUP([hv1]) -+AT_CLEANUP -+]) -+ -+OVN_FOR_EACH_NORTHD_NO_HV([ -+AT_SETUP([port up with slow northd]) -+ovn_start -+ -+sleep_northd() { -+ echo northd going to sleep -+ AT_CHECK([kill -STOP $(cat northd/ovn-northd.pid)]) -+} -+ -+wake_up_northd() { -+ echo northd going to sleep -+ AT_CHECK([kill -CONT $(cat northd/ovn-northd.pid)]) -+} -+ -+net_add n1 -+sim_add hv1 -+as hv1 -+ovs-vsctl add-br br-phys -+ovn_attach n1 br-phys 192.168.0.11 -+ -+check ovn-nbctl --wait=hv ls-add ls0 -+# Create a pilot port and wait it up to make sure we are ready for the real -+# tests, so that the counters measured are accurate. -+check ovn-nbctl --wait=hv lsp-add ls0 lsp-pilot -- lsp-set-addresses lsp-pilot "unknown" -+ovs-vsctl add-port br-int lsp-pilot -- set interface lsp-pilot external_ids:iface-id=lsp-pilot -+wait_for_ports_up -+check ovn-nbctl --wait=hv sync -+ -+check ovn-nbctl --wait=hv lsp-add ls0 lsp0-2 -- lsp-set-addresses lsp0-2 "aa:aa:aa:00:00:02 192.168.0.12" -+ovs-vsctl add-port br-int lsp0-2 -- set interface lsp0-2 external_ids:iface-id=lsp0-2 -+wait_for_ports_up -+check ovn-nbctl --wait=hv sync -+ -+sleep_northd -+check ovn-nbctl lsp-del lsp0-2 -+check ovn-nbctl lsp-add ls0 lsp0-2 -- lsp-set-addresses lsp0-2 "aa:aa:aa:00:00:02 192.168.0.12" -+wake_up_northd -+ -+check ovn-nbctl --wait=sb sync -+wait_for_ports_up -+ -+OVN_CLEANUP([hv1]) -+AT_CLEANUP -+]) -+ -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([gratuitous arp max timeout]) -+AT_KEYWORDS([slowtest]) -+TAG_UNSTABLE -+AT_SKIP_IF([test $HAVE_TCPDUMP = no]) -+ovn_start -+ -+check ovn-nbctl ls-add ls0 -+check ovn-nbctl lr-add lr0 -+check ovn-nbctl lrp-add lr0 lr0-ls0 f0:00:00:00:00:01 192.168.0.1/24 -+check ovn-nbctl lsp-add ls0 ls0-lr0 -- set Logical_Switch_Port ls0-lr0 \ -+ type=router options:router-port=lr0-ls0 addresses='"f0:00:00:00:00:01"' -+ -+check ovn-nbctl lsp-add ls0 ln_port -+check ovn-nbctl lsp-set-addresses ln_port unknown -+check ovn-nbctl lsp-set-type ln_port localnet -+check ovn-nbctl --wait=hv lsp-set-options ln_port network_name=physnet1 -+ -+net_add n1 -+sim_add hv1 -+as hv1 -+check ovs-vsctl \ -+ -- add-br br-phys \ -+ -- add-br br-eth0 -+ -+ovn_attach n1 br-phys 192.168.0.10 -+ -+check ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=physnet1:br-eth0 -+check ovs-vsctl add-port br-eth0 snoopvif -- set Interface snoopvif options:tx_pcap=hv1/snoopvif-tx.pcap options:rxq_pcap=hv1/snoopvif-rx.pcap -+ -+# set garp max timeout to 2s -+as hv1 check ovs-vsctl set Open_vSwitch . external-ids:garp-max-timeout-sec=2 -+ -+# Wait until the patch ports are created in hv1 to connect br-int to br-eth0 -+check ovn-nbctl set logical_router lr0 options:chassis=hv1 -+OVN_WAIT_PATCH_PORT_FLOWS(["ln_port"], ["hv1"]) -+ -+# sleep for 12s to get a garp every ~ 2s -+sleep 12 -+ -+n_arp=$(tcpdump -ner hv1/snoopvif-tx.pcap arp | wc -l) -+AT_CHECK([test $n_arp -ge 5 -a $n_arp -lt 10]) -+ -+# Temporarily remove lr0 chassis -+# Wait for hv confirmation to make sure chassis is removed before we reset pcap -+# Otherwise a garp might be sent after pcap have been reset but before chassis is removed -+check ovn-nbctl --wait=hv remove logical_router lr0 options chassis -+ -+as hv1 reset_pcap_file snoopvif hv1/snoopvif -+# set garp max timeout to 1s -+as hv1 check ovs-vsctl set Open_vSwitch . external-ids:garp-max-timeout-sec=1 -+check ovn-nbctl set logical_router lr0 options:chassis=hv1 -+ -+# sleep for 7s to get a garp every ~ 1s -+sleep 7 -+ -+n_arp=$(tcpdump -ner hv1/snoopvif-tx.pcap arp | wc -l) -+AT_CHECK([test $n_arp -ge 5 -a $n_arp -lt 10]) -+ -+OVN_CLEANUP([hv1]) -+ -+AT_CLEANUP -+]) -+ -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([Changing tunnel_key]) -+ovn_start -+ -+net_add n1 -+ -+sim_add hv1 -+as hv1 -+check ovs-vsctl add-br br-phys -+ovn_attach n1 br-phys 192.168.0.11 -+ -+check ovn-nbctl --wait=hv ls-add ls \ -+ -- lsp-add ls lsp1 \ -+ -- lsp-add ls ls-lr \ -+ -- lr-add lr \ -+ -- lrp-add lr lr-ls f0:00:00:00:00:f1 192.168.1.1/24 \ -+ -- set Logical_Switch_Port ls-lr \ -+ type=router \ -+ options:router-port=lr-ls \ -+ addresses=router \ -+ -- lrp-set-gateway-chassis lr-ls hv1 -+ -+sleep_controller hv1 -+ -+check ovn-nbctl --wait=sb set Logical_Switch ls other_config:requested-tnl-key=1000 -+check ovn-nbctl --wait=sb ls-del ls -+wake_up_controller hv1 -+ -+check ovn-nbctl --wait=hv sync -+ -+check ovn-nbctl --wait=hv ls-add ls1 \ -+ -- lsp-add ls1 ls1-lr \ -+ -- lrp-add lr lr-ls1 f0:00:00:00:00:f2 192.168.2.1/24 \ -+ -- set Logical_Switch_Port ls1-lr type=router options:router-port=lr-ls1 addresses=router \ -+ -- lrp-set-gateway-chassis lr-ls1 hv1 -+ -+check ovn-nbctl --wait=hv set Logical_Switch ls1 other_config:requested-tnl-key=1001 -+ -+OVN_CLEANUP([hv1]) -+ -+AT_CLEANUP -+]) -+ -+AT_SETUP([read-only sb db:pssl access with ssl-ciphers and ssl-protocols]) -+AT_SKIP_IF([test "$HAVE_OPENSSL" = no]) -+PKIDIR="$(cd $abs_top_builddir/tests && pwd)" -+AT_SKIP_IF([expr "$PKIDIR" : ".*[[ '\" -+\\]]"]) -+ -+: > .$1.db.~lock~ -+ovsdb-tool create ovn-sb.db "$abs_top_srcdir"/ovn-sb.ovsschema -+ -+# Add read-only remote to sb ovsdb-server -+AT_CHECK( -+ [ovsdb-tool transact ovn-sb.db \ -+ ['["OVN_Southbound", -+ {"op": "insert", -+ "table": "SB_Global", -+ "row": { -+ "connections": ["set", [["named-uuid", "xyz"]]]}}, -+ {"op": "insert", -+ "table": "Connection", -+ "uuid-name": "xyz", -+ "row": {"target": "pssl:0:127.0.0.1", -+ "read_only": true}}]']], [0], [ignore], [ignore]) -+ -+start_daemon ovsdb-server --remote=punix:ovn-sb.sock \ -+ --remote=db:OVN_Southbound,SB_Global,connections \ -+ --private-key="$PKIDIR/testpki-test2-privkey.pem" \ -+ --certificate="$PKIDIR/testpki-test2-cert.pem" \ -+ --ca-cert="$PKIDIR/testpki-cacert.pem" \ -+ --ssl-ciphers='HIGH:!aNULL:!MD5:@SECLEVEL=1' \ -+ --ssl-protocols='TLSv1,TLSv1.1,TLSv1.2' \ -+ ovn-sb.db -+ -+PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT]) -+ -+# read-only accesses should succeed -+AT_CHECK([ovn-sbctl --db=ssl:127.0.0.1:$TCP_PORT \ -+ --private-key=$PKIDIR/testpki-test-privkey.pem \ -+ --certificate=$PKIDIR/testpki-test-cert.pem \ -+ --ca-cert=$PKIDIR/testpki-cacert.pem \ -+ --ssl-ciphers='HIGH:!aNULL:!MD5:@SECLEVEL=1' \ -+ --ssl-protocols='TLSv1,TLSv1.1,TLSv1.2' \ -+ list SB_Global], [0], [stdout], [ignore]) -+AT_CHECK([ovn-sbctl --db=ssl:127.0.0.1:$TCP_PORT \ -+ --private-key=$PKIDIR/testpki-test-privkey.pem \ -+ --certificate=$PKIDIR/testpki-test-cert.pem \ -+ --ca-cert=$PKIDIR/testpki-cacert.pem \ -+ --ssl-ciphers='HIGH:!aNULL:!MD5:@SECLEVEL=1' \ -+ --ssl-protocols='TLSv1,TLSv1.1,TLSv1.2' \ -+ list Connection], [0], [stdout], [ignore]) -+ -+# write access should fail -+AT_CHECK([ovn-sbctl --db=ssl:127.0.0.1:$TCP_PORT \ -+ --private-key=$PKIDIR/testpki-test-privkey.pem \ -+ --certificate=$PKIDIR/testpki-test-cert.pem \ -+ --ca-cert=$PKIDIR/testpki-cacert.pem \ -+ --ssl-ciphers='HIGH:!aNULL:!MD5:@SECLEVEL=1' \ -+ --ssl-protocols='TLSv1,TLSv1.1,TLSv1.2' \ -+ chassis-add ch vxlan 1.2.4.8], [1], [ignore], -+[ovn-sbctl: transaction error: {"details":"insert operation not allowed when database server is in read only mode","error":"not allowed"} -+]) -+ -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+AT_CLEANUP -+ -+AT_SETUP([nb connection/ssl commands with ssl-ciphers and ssl-protocols]) -+AT_SKIP_IF([test "$HAVE_OPENSSL" = no]) -+PKIDIR="$(cd $abs_top_builddir/tests && pwd)" -+AT_SKIP_IF([expr "$PKIDIR" : ".*[[ '\" -+\\]]"]) -+ -+: > .$1.db.~lock~ -+ovsdb-tool create ovn-nb.db "$abs_top_srcdir"/ovn-nb.ovsschema -+ -+# Start nb db server using db connection/ssl entries (unpopulated initially) -+start_daemon ovsdb-server --remote=punix:ovnnb_db.sock \ -+ --remote=db:OVN_Northbound,NB_Global,connections \ -+ --private-key=db:OVN_Northbound,SSL,private_key \ -+ --certificate=db:OVN_Northbound,SSL,certificate \ -+ --ca-cert=db:OVN_Northbound,SSL,ca_cert \ -+ --ssl-ciphers='HIGH:!aNULL:!MD5:@SECLEVEL=1' \ -+ --ssl-protocols='TLSv1,TLSv1.1,TLSv1.2' \ -+ ovn-nb.db -+ -+# Populate SSL configuration entries in nb db -+AT_CHECK( -+ [ovn-nbctl set-ssl $PKIDIR/testpki-test-privkey.pem \ -+ $PKIDIR/testpki-test-cert.pem \ -+ $PKIDIR/testpki-cacert.pem], [0], [stdout], [ignore]) -+ -+# Populate a passive SSL connection in nb db -+AT_CHECK([ovn-nbctl set-connection pssl:0:127.0.0.1], [0], [stdout], [ignore]) -+ -+PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT]) -+ -+# Verify SSL connetivity to nb db server -+AT_CHECK([ovn-nbctl --db=ssl:127.0.0.1:$TCP_PORT \ -+ --private-key=$PKIDIR/testpki-test-privkey.pem \ -+ --certificate=$PKIDIR/testpki-test-cert.pem \ -+ --ca-cert=$PKIDIR/testpki-cacert.pem \ -+ --ssl-ciphers='HIGH:!aNULL:!MD5:@SECLEVEL=1' \ -+ --ssl-protocols='TLSv1,TLSv1.1,TLSv1.2' \ -+ list NB_Global], -+ [0], [stdout], [ignore]) -+AT_CHECK([ovn-nbctl --db=ssl:127.0.0.1:$TCP_PORT \ -+ --private-key=$PKIDIR/testpki-test-privkey.pem \ -+ --certificate=$PKIDIR/testpki-test-cert.pem \ -+ --ca-cert=$PKIDIR/testpki-cacert.pem \ -+ --ssl-ciphers='HIGH:!aNULL:!MD5:@SECLEVEL=1' \ -+ --ssl-protocols='TLSv1,TLSv1.1,TLSv1.2' \ -+ list Connection], -+ [0], [stdout], [ignore]) -+AT_CHECK([ovn-nbctl --db=ssl:127.0.0.1:$TCP_PORT \ -+ --private-key=$PKIDIR/testpki-test-privkey.pem \ -+ --certificate=$PKIDIR/testpki-test-cert.pem \ -+ --ca-cert=$PKIDIR/testpki-cacert.pem \ -+ --ssl-ciphers='HIGH:!aNULL:!MD5:@SECLEVEL=1' \ -+ --ssl-protocols='TLSv1,TLSv1.1,TLSv1.2' \ -+ get-connection], -+ [0], [stdout], [ignore]) -+ -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+AT_CLEANUP -+ -+AT_SETUP([sb connection/ssl commands with ssl-ciphers and ssl-protocols]) -+AT_SKIP_IF([test "$HAVE_OPENSSL" = no]) -+PKIDIR="$(cd $abs_top_builddir/tests && pwd)" -+AT_SKIP_IF([expr "$PKIDIR" : ".*[[ '\" -+\\]]"]) -+ -+: > .$1.db.~lock~ -+ovsdb-tool create ovn-sb.db "$abs_top_srcdir"/ovn-sb.ovsschema -+ -+# Start sb db server using db connection/ssl entries (unpopulated initially) -+start_daemon ovsdb-server --remote=punix:ovnsb_db.sock \ -+ --remote=db:OVN_Southbound,SB_Global,connections \ -+ --private-key=db:OVN_Southbound,SSL,private_key \ -+ --certificate=db:OVN_Southbound,SSL,certificate \ -+ --ca-cert=db:OVN_Southbound,SSL,ca_cert \ -+ --ssl-ciphers='HIGH:!aNULL:!MD5:@SECLEVEL=1' \ -+ --ssl-protocols='TLSv1,TLSv1.1,TLSv1.2' \ -+ ovn-sb.db -+ -+# Populate SSL configuration entries in sb db -+AT_CHECK( -+ [ovn-sbctl set-ssl $PKIDIR/testpki-test-privkey.pem \ -+ $PKIDIR/testpki-test-cert.pem \ -+ $PKIDIR/testpki-cacert.pem], [0], [stdout], [ignore]) -+ -+# Populate a passive SSL connection in sb db -+AT_CHECK([ovn-sbctl set-connection pssl:0:127.0.0.1], [0], [stdout], [ignore]) -+ -+PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT]) -+ -+# Verify SSL connetivity to sb db server -+AT_CHECK([ovn-sbctl --db=ssl:127.0.0.1:$TCP_PORT \ -+ --private-key=$PKIDIR/testpki-test-privkey.pem \ -+ --certificate=$PKIDIR/testpki-test-cert.pem \ -+ --ca-cert=$PKIDIR/testpki-cacert.pem \ -+ --ssl-ciphers='HIGH:!aNULL:!MD5:@SECLEVEL=1' \ -+ --ssl-protocols='TLSv1,TLSv1.1,TLSv1.2' \ -+ list SB_Global], -+ [0], [stdout], [ignore]) -+AT_CHECK([ovn-sbctl --db=ssl:127.0.0.1:$TCP_PORT \ -+ --private-key=$PKIDIR/testpki-test-privkey.pem \ -+ --certificate=$PKIDIR/testpki-test-cert.pem \ -+ --ca-cert=$PKIDIR/testpki-cacert.pem \ -+ --ssl-ciphers='HIGH:!aNULL:!MD5:@SECLEVEL=1' \ -+ --ssl-protocols='TLSv1,TLSv1.1,TLSv1.2' \ -+ list Connection], -+ [0], [stdout], [ignore]) -+AT_CHECK([ovn-sbctl --db=ssl:127.0.0.1:$TCP_PORT \ -+ --private-key=$PKIDIR/testpki-test-privkey.pem \ -+ --certificate=$PKIDIR/testpki-test-cert.pem \ -+ --ca-cert=$PKIDIR/testpki-cacert.pem \ -+ --ssl-ciphers='HIGH:!aNULL:!MD5:@SECLEVEL=1' \ -+ --ssl-protocols='TLSv1,TLSv1.1,TLSv1.2' \ -+ get-connection], -+ [0], [stdout], [ignore]) -+ -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+AT_CLEANUP -diff --git a/tests/scapy-server.py b/tests/scapy-server.py -new file mode 100755 -index 000000000..1cc616f70 ---- /dev/null -+++ b/tests/scapy-server.py -@@ -0,0 +1,81 @@ -+#!/usr/bin/env python3 -+ -+import argparse -+import time -+ -+import ovs.daemon -+import ovs.unixctl -+import ovs.unixctl.server -+ -+import binascii -+from scapy.all import * # noqa: F401,F403 -+from scapy.all import raw -+ -+ -+vlog = ovs.vlog.Vlog("scapy-server") -+exiting = False -+ -+ -+def exit(conn, argv, aux): -+ global exiting -+ -+ exiting = True -+ conn.reply(None) -+ -+ -+def process(data): -+ start_time = time.perf_counter() -+ vlog.info(f"received payload request: {data}") -+ try: -+ data = data.replace('\n', '') -+ return binascii.hexlify(raw(eval(data))).decode() -+ except Exception as e: -+ vlog.exception(f"failed to process payload request: {e}") -+ return "" -+ finally: -+ total_time = (time.perf_counter() - start_time) * 1000 -+ vlog.info(f"took {total_time:.2f}ms to process payload request") -+ -+ -+def payload(conn, argv, aux): -+ try: -+ conn.reply(process(argv[0])) -+ except Exception as e: -+ vlog.exception(f"failed to reply to payload request: {e}") -+ -+ -+def main(): -+ parser = argparse.ArgumentParser( -+ description="Scapy-based Frame Payload Generator") -+ parser.add_argument("--unixctl", help="UNIXCTL socket location or 'none'.") -+ -+ ovs.daemon.add_args(parser) -+ ovs.vlog.add_args(parser) -+ args = parser.parse_args() -+ ovs.daemon.handle_args(args) -+ ovs.vlog.handle_args(args) -+ -+ ovs.daemon.daemonize_start() -+ error, server = ovs.unixctl.server.UnixctlServer.create(args.unixctl) -+ if error: -+ ovs.util.ovs_fatal(error, "could not create unixctl server at %s" -+ % args.unixctl, vlog) -+ -+ ovs.unixctl.command_register("exit", "", 0, 0, exit, None) -+ ovs.unixctl.command_register("payload", "", 1, 1, payload, None) -+ ovs.daemon.daemonize_complete() -+ -+ vlog.info("scapy server ready") -+ -+ poller = ovs.poller.Poller() -+ while not exiting: -+ server.run() -+ server.wait(poller) -+ if exiting: -+ poller.immediate_wake() -+ poller.block() -+ server.close() -+ -+ -+if __name__ == '__main__': -+ main() -diff --git a/tests/system-common-macros.at b/tests/system-common-macros.at -index 97c6e433b..2dfad32bb 100644 ---- a/tests/system-common-macros.at -+++ b/tests/system-common-macros.at -@@ -59,7 +59,7 @@ m4_define([ADD_BR], [ovs-vsctl _ADD_BR([$1]) -- $2]) - # The existing 'port' or 'ovs-port' will be removed before new ones are added. - # - m4_define([ADD_VETH], -- [ AT_CHECK([ip link add $1 type veth peer name ovs-$1 || return 77]) -+ [ AT_CHECK([ip link add $1 type veth peer name ovs-$1]) - CONFIGURE_VETH_OFFLOADS([$1]) - AT_CHECK([ip link set $1 netns $2]) - AT_CHECK([ip link set dev ovs-$1 up]) -@@ -372,7 +372,7 @@ ADD_VETH(sw11, sw11, br-int, "192.168.2.2/24", "f0:00:00:02:02:03", \ - "192.168.2.1") - ADD_NAMESPACES(server) - ADD_VETH(s1, server, br-ext, "2001:1db8:3333::2/64", "f0:00:00:01:02:05", \ -- "2001:1db8:3333::1") -+ "2001:1db8:3333::1", "nodad") - - if test X"$1" = X"GR"; then - ovn-nbctl create Logical_Router name=R1 options:chassis=hv1 -@@ -409,9 +409,6 @@ ovn-nbctl lsp-add sw0 sw01 \ - ovn-nbctl lsp-add sw1 sw11 \ - -- lsp-set-addresses sw11 "f0:00:00:02:02:03 192.168.2.2" - --OVS_WAIT_UNTIL([test "$(ip netns exec server ip a | grep 2001:1db8:3333::2 | grep tentative)" = ""]) --OVS_WAIT_UNTIL([test "$(ip netns exec server ip a | grep fe80 | grep tentative)" = ""]) -- - AT_CHECK([ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext]) - ovn-nbctl lsp-add public public1 \ - -- lsp-set-addresses public1 unknown \ -diff --git a/tests/system-ovn-kmod.at b/tests/system-ovn-kmod.at -index b29e6b55a..3a533d5e6 100644 ---- a/tests/system-ovn-kmod.at -+++ b/tests/system-ovn-kmod.at -@@ -1,224 +1,5 @@ - AT_BANNER([system-ovn-kmod]) - --# SCTP and userspace conntrack do not mix. Therefore this --# test only can be run with kernel datapath. Otherwise, --# this is mostly a copy of existing load balancer tests --# in system-ovn.at --AT_SETUP([load balancing in gateway router - SCTP]) --AT_SKIP_IF([test $HAVE_SCTP = no]) --AT_SKIP_IF([test $HAVE_NC = no]) --AT_KEYWORDS([ovnlb sctp]) -- --# Make sure the SCTP kernel module is loaded. --LOAD_MODULE([sctp]) -- --CHECK_CONNTRACK() --CHECK_CONNTRACK_NAT() --ovn_start --OVS_TRAFFIC_VSWITCHD_START() --ADD_BR([br-int]) -- --# Set external-ids in br-int needed for ovn-controller --ovs-vsctl \ -- -- set Open_vSwitch . external-ids:system-id=hv1 \ -- -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ -- -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ -- -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ -- -- set bridge br-int fail-mode=secure other-config:disable-in-band=true -- --# Start ovn-controller --start_daemon ovn-controller -- --# Logical network: --# Two LRs - R1 and R2 that are connected to each other via LS "join" --# in 20.0.0.0/24 network. R1 has switchess foo (192.168.1.0/24) and --# bar (192.168.2.0/24) connected to it. R2 has alice (172.16.1.0/24) connected --# to it. R2 is a gateway router on which we add load-balancing rules. --# --# foo -- R1 -- join - R2 -- alice --# | --# bar ---- -- --ovn-nbctl create Logical_Router name=R1 --ovn-nbctl create Logical_Router name=R2 options:chassis=hv1 -- --ovn-nbctl ls-add foo --ovn-nbctl ls-add bar --ovn-nbctl ls-add alice --ovn-nbctl ls-add join -- --# Connect foo to R1 --ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24 --ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \ -- type=router options:router-port=foo addresses=\"00:00:01:01:02:03\" -- --# Connect bar to R1 --ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 192.168.2.1/24 --ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \ -- type=router options:router-port=bar addresses=\"00:00:01:01:02:04\" -- --# Connect alice to R2 --ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 172.16.1.1/24 --ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \ -- type=router options:router-port=alice addresses=\"00:00:02:01:02:03\" -- --# Connect R1 to join --ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 20.0.0.1/24 --ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \ -- type=router options:router-port=R1_join addresses='"00:00:04:01:02:03"' -- --# Connect R2 to join --ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 20.0.0.2/24 --ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \ -- type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"' -- --# Static routes. --ovn-nbctl lr-route-add R1 172.16.1.0/24 20.0.0.2 --ovn-nbctl lr-route-add R2 192.168.0.0/16 20.0.0.1 -- --# Logical port 'foo1' in switch 'foo'. --ADD_NAMESPACES(foo1) --ADD_VETH(foo1, foo1, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \ -- "192.168.1.1") --ovn-nbctl lsp-add foo foo1 \ ---- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2" -- --# Logical port 'alice1' in switch 'alice'. --ADD_NAMESPACES(alice1) --ADD_VETH(alice1, alice1, br-int, "172.16.1.2/24", "f0:00:00:01:02:04", \ -- "172.16.1.1") --ovn-nbctl lsp-add alice alice1 \ ---- lsp-set-addresses alice1 "f0:00:00:01:02:04 172.16.1.2" -- --# Logical port 'bar1' in switch 'bar'. --ADD_NAMESPACES(bar1) --ADD_VETH(bar1, bar1, br-int, "192.168.2.2/24", "f0:00:00:01:02:05", \ --"192.168.2.1") --ovn-nbctl lsp-add bar bar1 \ ---- lsp-set-addresses bar1 "f0:00:00:01:02:05 192.168.2.2" -- --# Config OVN load-balancer with a VIP. --uuid=`ovn-nbctl create load_balancer protocol=sctp vips:30.0.0.1="192.168.1.2,192.168.2.2"` --ovn-nbctl set logical_router R2 load_balancer=$uuid -- --# Config OVN load-balancer with another VIP (this time with ports). --ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:12345,192.168.2.2:12345"' -- --# Add SNAT rule to make sure that Load-balancing still works with a SNAT rule. --ovn-nbctl -- --id=@nat create nat type="snat" logical_ip=192.168.2.2 \ -- external_ip=30.0.0.2 -- add logical_router R2 nat @nat -- --# Wait for ovn-controller to catch up. --ovn-nbctl --wait=hv sync --OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \ --grep 'nat(dst=192.168.2.2:12345)']) -- --# Start webservers in 'foo1', 'bar1'. --OVS_START_L7([foo1], [sctp]) --OVS_START_L7([bar1], [sctp]) -- --on_exit "ovs-ofctl -O OpenFlow13 dump-flows br-int" -- --dnl Should work with the virtual IP address through NAT --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([alice1], [nc --sctp --recv-only 30.0.0.1 12345 > client$i.log]) --done -- --dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | --sed -e 's/zone=[[0-9]]*/zone=/' | --sed -e 's/vtag_orig=[[0-9]]*/vtag_orig=/' | --sed -e 's/vtag_reply=[[0-9]]*/vtag_reply=/' | uniq], [0], [dnl --sctp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=,vtag_orig=,vtag_reply=) --sctp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=,vtag_orig=,vtag_reply=) --]) -- --dnl Test load-balancing that includes L4 ports in NAT. --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([alice1], [nc --sctp --recv-only 30.0.0.2 8000 > clients$i.log]) --done -- --dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | --sed -e 's/zone=[[0-9]]*/zone=/' | --sed -e 's/vtag_orig=[[0-9]]*/vtag_orig=/' | --sed -e 's/vtag_reply=[[0-9]]*/vtag_reply=/' | uniq], [0], [dnl --sctp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=,vtag_orig=,vtag_reply=) --sctp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2,protoinfo=(state=,vtag_orig=,vtag_reply=) --]) -- --check_est_flows () { -- n=$(ovs-ofctl dump-flows br-int table=15 | grep "+est" \ -- | grep "ct_mark=$1" | sed -n 's/.*n_packets=\([[0-9]]\{1,\}\).*/\1/p') -- -- echo "n_packets=$n" -- test -n "$n" && test "$n" != "0" --} -- --OVS_WAIT_UNTIL([check_est_flows 0x2], [check established flows]) -- -- --ovn-nbctl set logical_router R2 options:lb_force_snat_ip="20.0.0.2" -- --# Destroy the load balancer and create again. ovn-controller will --# clear the OF flows and re add again and clears the n_packets --# for these flows. --ovn-nbctl destroy load_balancer $uuid --uuid=`ovn-nbctl create load_balancer protocol=sctp vips:30.0.0.1="192.168.1.2,192.168.2.2"` --ovn-nbctl set logical_router R2 load_balancer=$uuid -- --check ovs-appctl dpctl/flush-conntrack -- --# Config OVN load-balancer with another VIP (this time with ports). --ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:12345,192.168.2.2:12345"' -- --ovn-nbctl list load_balancer --ovn-sbctl dump-flows R2 --OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-flows br-int table=45 | grep 'nat(src=20.0.0.2)']) -- --dnl Test load-balancing that includes L4 ports in NAT. --for i in `seq 1 20`; do -- echo Request $i -- NS_CHECK_EXEC([alice1], [nc --sctp --recv-only 30.0.0.2 8000 > clients$i.log]) --done -- --dnl Each server should have at least one connection. --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | --sed -e 's/zone=[[0-9]]*/zone=/' | --sed -e 's/vtag_orig=[[0-9]]*/vtag_orig=/' | --sed -e 's/vtag_reply=[[0-9]]*/vtag_reply=/' | uniq], [0], [dnl --sctp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,mark=10,protoinfo=(state=,vtag_orig=,vtag_reply=) --sctp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,mark=10,protoinfo=(state=,vtag_orig=,vtag_reply=) --]) -- --AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0.2) | --sed -e 's/zone=[[0-9]]*/zone=/' | --sed -e 's/vtag_orig=[[0-9]]*/vtag_orig=/' | --sed -e 's/vtag_reply=[[0-9]]*/vtag_reply=/' | uniq], [0], [dnl --sctp,orig=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=,vtag_orig=,vtag_reply=) --sctp,orig=(src=172.16.1.2,dst=192.168.2.2,sport=,dport=),reply=(src=192.168.2.2,dst=20.0.0.2,sport=,dport=),zone=,protoinfo=(state=,vtag_orig=,vtag_reply=) --]) -- --OVS_WAIT_UNTIL([check_est_flows 0xa], [check established flows]) -- --OVS_APP_EXIT_AND_WAIT([ovn-controller]) -- --as ovn-sb --OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -- --as ovn-nb --OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -- --as northd --OVS_APP_EXIT_AND_WAIT([ovn-northd]) -- --as --OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d --/connection dropped.*/d"]) --AT_CLEANUP -- - OVN_FOR_EACH_NORTHD([ - AT_SETUP([load balancing affinity sessions - IPv4]) - AT_KEYWORDS([ovnlb]) -@@ -365,13 +146,13 @@ tcp,orig=(src=172.16.1.2,dst=172.16.1.100,sport=,dport=),reply - ]) - - dp_key=$(printf "0x%x" $(fetch_column datapath tunnel_key external_ids:name=R2)) --AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=78 --no-stats | sed -e 's/load:0xc0a80[[0-9]]02/load:0xc0a8002/'], [0], [dnl -+AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=78 --no-stats | strip_cookie | sed -e 's/load:0xc0a80[[0-9]]02/load:0xc0a8002/'], [0], [dnl - table=78, idle_timeout=60, tcp,metadata=$dp_key,nw_src=172.16.1.2,nw_dst=172.16.1.100,tp_dst=8080 actions=load:0x1->NXM_NX_REG10[[14]],load:0xc0a8002->NXM_NX_REG4[[]],load:0x50->NXM_NX_REG8[[0..15]] - ]) - - check_affinity_flows () { --n1=$(ovs-ofctl dump-flows br-int table=15 |awk '/priority=150,ct_state=\+new\+trk,ip,reg4=0xc0a80102/{print substr($4,11,length($4)-11)}') --n2=$(ovs-ofctl dump-flows br-int table=15 |awk '/priority=150,ct_state=\+new\+trk,ip,reg4=0xc0a80202/{print substr($4,11,length($4)-11)}') -+n1=$(ovs-ofctl dump-flows br-int table=15 |awk '/priority=150,ct_state=\+new\+trk,ip,reg4=0xc0a80102,.*nw_dst=172.16.1.100/{print substr($4,11,length($4)-11)}') -+n2=$(ovs-ofctl dump-flows br-int table=15 |awk '/priority=150,ct_state=\+new\+trk,ip,reg4=0xc0a80202,.*nw_dst=172.16.1.100/{print substr($4,11,length($4)-11)}') - [[ $n1 -gt 0 -a $n2 -eq 0 ]] || [[ $n1 -eq 0 -a $n2 -gt 0 ]] - echo $? - } -@@ -588,31 +369,27 @@ ovn-nbctl lr-route-add R2 fd12::/64 fd20::1 - # Logical port 'foo1' in switch 'foo'. - ADD_NAMESPACES(foo1) - ADD_VETH(foo1, foo1, br-int, "fd11::2/64", "f0:00:00:01:02:03", \ -- "fd11::1") --OVS_WAIT_UNTIL([test "$(ip -n foo1 a | grep fd11::2 | grep tentative)" = ""]) -+ "fd11::1", "nodad") - ovn-nbctl lsp-add foo foo1 \ - -- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd11::2" - - # Logical port 'alice1' in switch 'alice'. - ADD_NAMESPACES(alice1) - ADD_VETH(alice1, alice1, br-int, "fd72::2/64", "f0:00:00:01:02:04", \ -- "fd72::1") --OVS_WAIT_UNTIL([test "$(ip -n alice1 a | grep fd72::2 | grep tentative)" = ""]) -+ "fd72::1", "nodad") - ovn-nbctl lsp-add alice alice1 \ - -- lsp-set-addresses alice1 "f0:00:00:01:02:04 fd72::2" - - # Logical port 'bar1' in switch 'bar'. - ADD_NAMESPACES(bar1) - ADD_VETH(bar1, bar1, br-int, "fd12::2/64", "f0:00:00:01:02:05", \ --"fd12::1") --OVS_WAIT_UNTIL([test "$(ip -n bar1 a | grep fd12::2 | grep tentative)" = ""]) -+ "fd12::1", "nodad") - ovn-nbctl lsp-add bar bar1 \ - -- lsp-set-addresses bar1 "f0:00:00:01:02:05 fd12::2" - - ADD_NAMESPACES(bar2) - ADD_VETH(bar2, bar2, br-int, "fd12::3/64", "e0:00:00:01:02:05", \ --"fd12::1") --OVS_WAIT_UNTIL([test "$(ip -n bar2 a | grep fd12::3 | grep tentative)" = ""]) -+ "fd12::1", "nodad") - ovn-nbctl lsp-add bar bar2 \ - -- lsp-set-addresses bar2 "e0:00:00:01:02:05 fd12::3" - -@@ -666,13 +443,13 @@ tcp,orig=(src=fd72::2,dst=fd30::1,sport=,dport=),reply=(src=fd - ]) - - dp_key=$(printf "0x%x" $(fetch_column datapath tunnel_key external_ids:name=R2)) --AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=78 --no-stats | sed -e 's/load:0xfd1[[0-9]]000000000000/load:0xfd1000000000000/'], [0], [dnl -+AT_CHECK_UNQUOTED([ovs-ofctl dump-flows br-int table=78 --no-stats | strip_cookie | sed -e 's/load:0xfd1[[0-9]]000000000000/load:0xfd1000000000000/'], [0], [dnl - table=78, idle_timeout=60, tcp6,metadata=$dp_key,ipv6_src=fd72::2,ipv6_dst=fd30::1,tp_dst=8080 actions=load:0x1->NXM_NX_REG10[[14]],load:0x2->NXM_NX_XXREG1[[0..63]],load:0xfd1000000000000->NXM_NX_XXREG1[[64..127]],load:0x50->NXM_NX_REG8[[0..15]] - ]) - - check_affinity_flows () { --n1=$(ovs-ofctl dump-flows br-int table=15 |awk '/priority=150,ct_state=\+new\+trk,ipv6,reg4=0xfd110000/{print substr($4,11,length($4)-11)}') --n2=$(ovs-ofctl dump-flows br-int table=15 |awk '/priority=150,ct_state=\+new\+trk,ipv6,reg4=0xfd120000/{print substr($4,11,length($4)-11)}') -+n1=$(ovs-ofctl dump-flows br-int table=15 |awk '/priority=150,ct_state=\+new\+trk,ipv6,reg4=0xfd110000,.*ipv6_dst=fd30::1\s/{print substr($4,11,length($4)-11)}') -+n2=$(ovs-ofctl dump-flows br-int table=15 |awk '/priority=150,ct_state=\+new\+trk,ipv6,reg4=0xfd120000,.*ipv6_dst=fd30::1\s/{print substr($4,11,length($4)-11)}') - [[ $n1 -gt 0 -a $n2 -eq 0 ]] || [[ $n1 -eq 0 -a $n2 -gt 0 ]] - echo $? - } -@@ -1115,3 +892,156 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d - /connection dropped.*/d"]) - AT_CLEANUP - ]) -+ -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([LR with SNAT fragmentation needed for external server]) -+AT_KEYWORDS([ovnlb]) -+ -+CHECK_CONNTRACK() -+CHECK_CONNTRACK_NAT() -+ -+ovn_start -+OVS_TRAFFIC_VSWITCHD_START() -+ADD_BR([br-int]) -+ADD_BR([br-ext]) -+ -+dnl Logical network: -+dnl 2 logical switches "public" (192.168.1.0/24) and "internal" (172.16.1.0/24) -+dnl connected to a router lr. -+dnl internal has a client. -+dnl server is connected through localnet. -+dnl -+dnl Server IP 192.168.1.2 MTU 900 -+dnl Client IP 172.16.1.2 MTU 800 -+dnl -+dnl SNAT for internal 172.16.1.2/24 with router ip 192.168.1.1. -+ -+check ovs-ofctl add-flow br-ext action=normal -+# Set external-ids in br-int needed for ovn-controller -+check ovs-vsctl \ -+ -- set Open_vSwitch . external-ids:system-id=hv1 \ -+ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ -+ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ -+ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ -+ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true \ -+ -- set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext -+ -+dnl Start ovn-controller -+start_daemon ovn-controller -+ -+check ovn-nbctl lr-add lr -+check ovn-nbctl ls-add internal -+check ovn-nbctl ls-add public -+ -+check ovn-nbctl lrp-add lr lr-pub 00:00:01:01:02:03 192.168.1.1/24 -+check ovn-nbctl lsp-add public pub-lr -- set Logical_Switch_Port pub-lr \ -+ type=router options:router-port=lr-pub addresses=\"00:00:01:01:02:03\" -+ -+check ovn-nbctl lrp-add lr lr-internal 00:00:01:01:02:04 172.16.1.1/24 -+check ovn-nbctl lsp-add internal internal-lr -- set Logical_Switch_Port internal-lr \ -+ type=router options:router-port=lr-internal addresses=\"00:00:01:01:02:04\" -+ -+ovn-nbctl lsp-add public ln_port \ -+ -- lsp-set-addresses ln_port unknown \ -+ -- lsp-set-type ln_port localnet \ -+ -- lsp-set-options ln_port network_name=phynet -+ -+ADD_NAMESPACES(server) -+ADD_VETH([server], [server], [br-ext], ["192.168.1.2/24"], -+ ["f0:00:00:01:02:03"], ["192.168.1.1"]) -+NS_EXEC([server], [ip l set dev server mtu 900]) -+NS_EXEC([server], [ip l show dev server]) -+ -+ADD_NAMESPACES(client) -+ADD_VETH([client], [client], [br-int], ["172.16.1.2/24"], -+ ["f0:00:0f:01:02:03"], ["172.16.1.1"]) -+NS_EXEC([client], [ip l set dev client mtu 800]) -+NS_EXEC([client], [ip l show dev client]) -+check ovn-nbctl lsp-add internal client \ -+ -- lsp-set-addresses client "f0:00:0f:01:02:03 172.16.1.2" -+ -+dnl Config OVN load-balancer with a VIP. (not necessary, but if we do not -+dnl have a load balancer and comment out snat, we will receive a stray fragment -+dnl on the client side.) -+dnl check ovn-nbctl lb-add lb1 192.168.1.20:4242 172.16.1.2:4242 udp -+dnl check ovn-nbctl lr-lb-add lr lb1 -+check ovn-nbctl set logical_router lr options:chassis=hv1 -+check ovn-nbctl set logical_router_port lr-internal options:gateway_mtu=800 -+ -+check ovn-nbctl lr-nat-add lr snat 192.168.1.1 172.16.1.2 -+ -+check ovn-nbctl --wait=hv sync -+ -+ovn-nbctl show -+ovs-vsctl show -+ovn-appctl -t ovn-controller vlog/set vconn:file:dbg pinctrl:file:dbg -+ -+AT_DATA([server.py], [dnl -+import socket -+ -+sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) -+ -+server_address = '192.168.1.2' -+server_port = 4242 -+ -+server = (server_address, server_port) -+sock.bind(server) -+print("Listening on ", server_address, ":", str(server_port), flush=True) -+ -+while True: -+ payload, client_address = sock.recvfrom(1000) -+ print("Received data from ", str(client_address), ": ", payload) -+ sent = sock.sendto(b"x" * 1017, client_address) -+ print("Sent back: ", str(sent), "bytes", flush=True) -+]) -+NETNS_DAEMONIZE([server], [$PYTHON3 ./server.py > server.log], [server.pid]) -+ -+dnl Collect packets on server side. -+NETNS_DAEMONIZE([server], [tcpdump -l -U -i server -vnne \ -+ 'ip and (icmp or udp)' > server.tcpdump 2>server_err], [tcpdump0.pid]) -+OVS_WAIT_UNTIL([grep "listening" server_err]) -+ -+dnl Collect packets on client side. -+NETNS_DAEMONIZE([client], [tcpdump -l -U -i client -vnne \ -+ 'ip and (icmp or udp)' > client.tcpdump 2>client_err], [tcpdump1.pid]) -+OVS_WAIT_UNTIL([grep "listening" client_err]) -+ -+dnl Send two packets to the server with a short interval. -+dnl First packet should generate 'needs frag', the second should result in -+dnl corectly fragmented reply. -+AT_DATA([client.py], [dnl -+import socket -+import time -+ -+sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) -+sock.sendto(b"x" * 7, ("192.168.1.2", 4242)) -+time.sleep(1) -+sock.sendto(b"x" * 7, ("192.168.1.2", 4242)) -+time.sleep(5) -+]) -+NS_CHECK_EXEC([client], [$PYTHON3 ./client.py]) -+ -+dnl Expecting 2 outgoing packets and 2 fragments back - 8 lines total. -+OVS_WAIT_UNTIL([test "$(cat client.tcpdump | wc -l)" = "8"]) -+AT_CHECK([test $(grep -c "need to frag (mtu 800)" server.tcpdump) -eq 1]) -+ -+ovn-appctl -t ovn-controller vlog/set info -+ -+OVS_APP_EXIT_AND_WAIT([ovn-controller]) -+ -+as ovn-sb -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+ -+as ovn-nb -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+ -+as northd -+OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE]) -+ -+as -+OVS_TRAFFIC_VSWITCHD_STOP([" -+ /failed to query port patch-.*/d -+ /connection dropped.*/d -+"]) -+AT_CLEANUP -+]) -diff --git a/tests/system-ovn.at b/tests/system-ovn.at -index 59d0cb2a0..213483176 100644 ---- a/tests/system-ovn.at -+++ b/tests/system-ovn.at -@@ -251,24 +251,21 @@ ovn-nbctl lr-route-add R2 fd12::/64 fd00::1 - # Logical port 'foo1' in switch 'foo'. - ADD_NAMESPACES(foo1) - ADD_VETH(foo1, foo1, br-int, "fd11::2/64", "f0:00:00:01:02:03", \ -- "fd11::1") --OVS_WAIT_UNTIL([test "$(ip netns exec foo1 ip a | grep fd11::2 | grep tentative)" = ""]) -+ "fd11::1", "nodad") - ovn-nbctl lsp-add foo foo1 \ - -- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd11::2" - - # Logical port 'alice1' in switch 'alice'. - ADD_NAMESPACES(alice1) - ADD_VETH(alice1, alice1, br-int, "fd21::2/64", "f0:00:00:01:02:04", \ -- "fd21::1") --OVS_WAIT_UNTIL([test "$(ip netns exec alice1 ip a | grep fd21::2 | grep tentative)" = ""]) -+ "fd21::1", "nodad") - ovn-nbctl lsp-add alice alice1 \ - -- lsp-set-addresses alice1 "f0:00:00:01:02:04 fd21::2" - - # Logical port 'bar1' in switch 'bar'. - ADD_NAMESPACES(bar1) - ADD_VETH(bar1, bar1, br-int, "fd12::2/64", "f0:00:00:01:02:05", \ -- "fd12::1") --OVS_WAIT_UNTIL([test "$(ip netns exec bar1 ip a | grep fd12::2 | grep tentative)" = ""]) -+ "fd12::1", "nodad") - ovn-nbctl lsp-add bar bar1 \ - -- lsp-set-addresses bar1 "f0:00:00:01:02:05 fd12::2" - -@@ -538,16 +535,14 @@ ovn-nbctl lr-route-add R2 fd10::/64 fd20::1 - # Logical port 'foo1' in switch 'foo'. - ADD_NAMESPACES(foo1) - ADD_VETH(foo1, foo1, br-int, "fd10::2/64", "f0:00:00:01:02:03", \ -- "fd10::1") --OVS_WAIT_UNTIL([test "$(ip netns exec foo1 ip a | grep fd10::2 | grep tentative)" = ""]) -+ "fd10::1", "nodad") - ovn-nbctl lsp-add foo foo1 \ - -- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd10::2" - - # Logical port 'alice1' in switch 'alice'. - ADD_NAMESPACES(alice1) - ADD_VETH(alice1, alice1, br-int, "fd30::2/64", "f0:00:00:01:02:04", \ -- "fd30::1") --OVS_WAIT_UNTIL([test "$(ip netns exec alice1 ip a | grep fd30::2 | grep tentative)" = ""]) -+ "fd30::1", "nodad") - ovn-nbctl lsp-add alice alice1 \ - -- lsp-set-addresses alice1 "f0:00:00:01:02:04 fd30::2" - -@@ -908,32 +903,28 @@ ovn-nbctl set logical_router R3 options:dnat_force_snat_ip=fd20::3 - # Logical port 'foo1' in switch 'foo'. - ADD_NAMESPACES(foo1) - ADD_VETH(foo1, foo1, br-int, "fd11::2/64", "f0:00:00:01:02:03", \ -- "fd11::1") --OVS_WAIT_UNTIL([test "$(ip netns exec foo1 ip a | grep fd11::2 | grep tentative)" = ""]) -+ "fd11::1", "nodad") - ovn-nbctl lsp-add foo foo1 \ - -- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd11::2" - - # Logical port 'alice1' in switch 'alice'. - ADD_NAMESPACES(alice1) - ADD_VETH(alice1, alice1, br-int, "fd30::3/64", "f0:00:00:01:02:04", \ -- "fd30::1") --OVS_WAIT_UNTIL([test "$(ip netns exec alice1 ip a | grep fd30::3 | grep tentative)" = ""]) -+ "fd30::1", "nodad") - ovn-nbctl lsp-add alice alice1 \ - -- lsp-set-addresses alice1 "f0:00:00:01:02:04 fd30::3" - - # Logical port 'bar1' in switch 'bar'. - ADD_NAMESPACES(bar1) - ADD_VETH(bar1, bar1, br-int, "fd12::2/64", "f0:00:00:01:02:05", \ -- "fd12::1") --OVS_WAIT_UNTIL([test "$(ip netns exec bar1 ip a | grep fd12::2 | grep tentative)" = ""]) -+ "fd12::1", "nodad") - ovn-nbctl lsp-add bar bar1 \ - -- lsp-set-addresses bar1 "f0:00:00:01:02:05 fd12::2" - - # Logical port 'bob1' in switch 'bob'. - ADD_NAMESPACES(bob1) - ADD_VETH(bob1, bob1, br-int, "fd30::4/64", "f0:00:00:01:02:06", \ -- "fd30::2") --OVS_WAIT_UNTIL([test "$(ip netns exec bob1 ip a | grep fd30::4 | grep tentative)" = ""]) -+ "fd30::2", "nodad") - ovn-nbctl lsp-add bob bob1 \ - -- lsp-set-addresses bob1 "f0:00:00:01:02:06 fd30::4" - -@@ -1149,8 +1140,7 @@ ovn-nbctl lsp-add foo foo1 \ - - ADD_NAMESPACES(foo16) - ADD_VETH(foo16, foo16, br-int, "fd11::2/64", "f0:00:00:02:02:03", \ -- "fd11::1") --OVS_WAIT_UNTIL([test "$(ip netns exec foo16 ip a | grep fd11::2 | grep tentative)" = ""]) -+ "fd11::1", "nodad") - ovn-nbctl lsp-add foo foo16 \ - -- lsp-set-addresses foo16 "f0:00:00:02:02:03 fd11::2" - -@@ -1163,8 +1153,7 @@ ovn-nbctl lsp-add alice alice1 \ - - ADD_NAMESPACES(alice16) - ADD_VETH(alice16, alice16, br-int, "fd30::3/64", "f0:00:00:02:02:04", \ -- "fd30::1") --OVS_WAIT_UNTIL([test "$(ip netns exec alice16 ip a | grep fd30::3 | grep tentative)" = ""]) -+ "fd30::1", "nodad") - ovn-nbctl lsp-add alice alice16 \ - -- lsp-set-addresses alice16 "f0:00:00:02:02:04 fd30::3" - -@@ -1177,8 +1166,7 @@ ovn-nbctl lsp-add bar bar1 \ - - ADD_NAMESPACES(bar16) - ADD_VETH(bar16, bar16, br-int, "fd12::2/64", "f0:00:00:02:02:05", \ -- "fd12::1") --OVS_WAIT_UNTIL([test "$(ip netns exec bar16 ip a | grep fd12::2 | grep tentative)" = ""]) -+ "fd12::1", "nodad") - ovn-nbctl lsp-add bar bar16 \ - -- lsp-set-addresses bar16 "f0:00:00:02:02:05 fd12::2" - -@@ -1191,8 +1179,7 @@ ovn-nbctl lsp-add bob bob1 \ - - ADD_NAMESPACES(bob16) - ADD_VETH(bob16, bob16, br-int, "fd30::4/64", "f0:00:00:02:02:06", \ -- "fd30::2") --OVS_WAIT_UNTIL([test "$(ip netns exec bob16 ip a | grep fd30::4 | grep tentative)" = ""]) -+ "fd30::2", "nodad") - ovn-nbctl lsp-add bob bob16 \ - -- lsp-set-addresses bob16 "f0:00:00:02:02:06 fd30::4" - -@@ -2376,14 +2363,10 @@ ADD_NAMESPACES(server) - ADD_VETH(s1, server, br-ext, "172.16.1.100/24", "1a:00:00:00:00:01", \ - "172.16.1.1") - --OVS_WAIT_UNTIL([test "$(ip netns exec server ip a | grep fe80 | grep tentative)" = ""]) -- - ADD_NAMESPACES(client) - ADD_VETH(c1, client, br-ext, "172.16.1.110/24", "1a:00:00:00:00:02", \ - "172.16.1.1") - --OVS_WAIT_UNTIL([test "$(ip netns exec client ip a | grep fe80 | grep tentative)" = ""]) -- - # Start webservers in 'server'. - OVS_START_L7([server], [http]) - -@@ -3670,32 +3653,28 @@ ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \ - # Logical port 'foo1' in switch 'foo'. - ADD_NAMESPACES(foo1) - ADD_VETH(foo1, foo1, br-int, "fd11::2/64", "f0:00:00:01:02:03", \ -- "fd11::1") --OVS_WAIT_UNTIL([test "$(ip netns exec foo1 ip a | grep fd11::2 | grep tentative)" = ""]) -+ "fd11::1", "nodad") - ovn-nbctl lsp-add foo foo1 \ - -- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd11::2" - - # Logical port 'foo2' in switch 'foo'. - ADD_NAMESPACES(foo2) - ADD_VETH(foo2, foo2, br-int, "fd11::3/64", "f0:00:00:01:02:06", \ -- "fd11::1") --OVS_WAIT_UNTIL([test "$(ip netns exec foo2 ip a | grep fd11::3 | grep tentative)" = ""]) -+ "fd11::1", "nodad") - ovn-nbctl lsp-add foo foo2 \ - -- lsp-set-addresses foo2 "f0:00:00:01:02:06 fd11::3" - - # Logical port 'bar1' in switch 'bar'. - ADD_NAMESPACES(bar1) - ADD_VETH(bar1, bar1, br-int, "fd12::2/64", "f0:00:00:01:02:04", \ -- "fd12::1") --OVS_WAIT_UNTIL([test "$(ip netns exec bar1 ip a | grep fd12::2 | grep tentative)" = ""]) -+ "fd12::1", "nodad") - ovn-nbctl lsp-add bar bar1 \ - -- lsp-set-addresses bar1 "f0:00:00:01:02:04 fd12::2" - - # Logical port 'alice1' in switch 'alice'. - ADD_NAMESPACES(alice1) - ADD_VETH(alice1, alice1, br-int, "fd20::2/64", "f0:00:00:01:02:05", \ -- "fd20::1") --OVS_WAIT_UNTIL([test "$(ip netns exec alice1 ip a | grep fd20::2 | grep tentative)" = ""]) -+ "fd20::1", "nodad") - ovn-nbctl lsp-add alice alice1 \ - -- lsp-set-addresses alice1 "f0:00:00:01:02:05 fd20::2" - -@@ -4018,32 +3997,28 @@ ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \ - # Logical port 'foo1' in switch 'foo'. - ADD_NAMESPACES(foo1) - ADD_VETH(foo1, foo1, br-int, "fd11::2/64", "f0:00:00:01:02:03", \ -- "fd11::1") --OVS_WAIT_UNTIL([test "$(ip netns exec foo1 ip a | grep fd11::2 | grep tentative)" = ""]) -+ "fd11::1", "nodad") - ovn-nbctl lsp-add foo foo1 \ - -- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd11::2" - - # Logical port 'foo2' in switch 'foo'. - ADD_NAMESPACES(foo2) - ADD_VETH(foo2, foo2, br-int, "fd11::3/64", "f0:00:00:01:02:06", \ -- "fd11::1") --OVS_WAIT_UNTIL([test "$(ip netns exec foo2 ip a | grep fd11::3 | grep tentative)" = ""]) -+ "fd11::1", "nodad") - ovn-nbctl lsp-add foo foo2 \ - -- lsp-set-addresses foo2 "f0:00:00:01:02:06 fd11::3" - - # Logical port 'bar1' in switch 'bar'. - ADD_NAMESPACES(bar1) - ADD_VETH(bar1, bar1, br-int, "fd12::2/64", "f0:00:00:01:02:04", \ -- "fd12::1") --OVS_WAIT_UNTIL([test "$(ip netns exec bar1 ip a | grep fd12::2 | grep tentative)" = ""]) -+ "fd12::1", "nodad") - ovn-nbctl lsp-add bar bar1 \ - -- lsp-set-addresses bar1 "f0:00:00:01:02:04 fd12::2" - - # Logical port 'alice1' in switch 'alice'. - ADD_NAMESPACES(alice1) - ADD_VETH(alice1, alice1, br-int, "fd20::2/64", "f0:00:00:01:02:05", \ -- "fd20::1") --OVS_WAIT_UNTIL([test "$(ip netns exec alice1 ip a | grep fd20::2 | grep tentative)" = ""]) -+ "fd20::1", "nodad") - ovn-nbctl lsp-add alice alice1 \ - -- lsp-set-addresses alice1 "f0:00:00:01:02:05 fd20::2" - -@@ -4928,8 +4903,7 @@ ovn-nbctl lsp-add sw sw-rtr \ - -- lsp-set-options sw-rtr router-port=rtr-sw - - ADD_NAMESPACES(lsp) --ADD_VETH(lsp, lsp, br-int, "4200::1/64", "00:00:00:00:00:01", "4200::00ff") --OVS_WAIT_UNTIL([test "$(ip netns exec lsp ip a | grep 4200::1 | grep tentative)" = ""]) -+ADD_VETH(lsp, lsp, br-int, "4200::1/64", "00:00:00:00:00:01", "4200::00ff", "nodad") - ovn-nbctl --wait=hv -t 3 sync - - # Start IPv6 TCP server on lsp. -@@ -5058,8 +5032,8 @@ ADD_NAMESPACES(sw0-p2-rej) - ADD_VETH(sw0-p2-rej, sw0-p2-rej, br-int, "10.0.0.4/24", "50:54:00:00:00:04", \ - "10.0.0.1") - --NS_CHECK_EXEC([sw0-p1-rej], [ip a a aef0::3/64 dev sw0-p1-rej], [0]) --NS_CHECK_EXEC([sw0-p2-rej], [ip a a aef0::4/64 dev sw0-p2-rej], [0]) -+NS_CHECK_EXEC([sw0-p1-rej], [ip a a aef0::3/64 dev sw0-p1-rej nodad], [0]) -+NS_CHECK_EXEC([sw0-p2-rej], [ip a a aef0::4/64 dev sw0-p2-rej nodad], [0]) - - ADD_NAMESPACES(sw1-p1-rej) - ADD_VETH(sw1-p1-rej, sw1-p1-rej, br-int, "20.0.0.3/24", "40:54:00:00:00:03", \ -@@ -5099,9 +5073,6 @@ NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -l -nn -i sw0-p2-rej tcp port 80 > sw0-p2-r - #Wait for tcpdump to get started before generating first packets - OVS_WAIT_UNTIL([test 1 = $(cat err | grep -c listening)]) - --OVS_WAIT_UNTIL([test "$(ip netns exec sw0-p1-rej ip a | grep aef0::3 | grep tentative)" = ""]) --OVS_WAIT_UNTIL([test "$(ip netns exec sw0-p2-rej ip a | grep aef0::4 | grep tentative)" = ""]) -- - OVS_WAIT_UNTIL([ - ip netns exec sw0-p2-rej nc -vz6 aef0::3 80 2>&1 | grep -i 'connection refused' - ]) -@@ -5308,8 +5279,8 @@ ADD_NAMESPACES(sw0-p2-rej) - ADD_VETH(sw0-p2-rej, sw0-p2-rej, br-int, "10.0.0.4/24", "50:54:00:00:00:04", \ - "10.0.0.1") - --NS_CHECK_EXEC([sw0-p1-rej], [ip a a aef0::3/64 dev sw0-p1-rej], [0]) --NS_CHECK_EXEC([sw0-p2-rej], [ip a a aef0::4/64 dev sw0-p2-rej], [0]) -+NS_CHECK_EXEC([sw0-p1-rej], [ip a a aef0::3/64 dev sw0-p1-rej nodad], [0]) -+NS_CHECK_EXEC([sw0-p2-rej], [ip a a aef0::4/64 dev sw0-p2-rej nodad], [0]) - - ADD_NAMESPACES(sw1-p1-rej) - ADD_VETH(sw1-p1-rej, sw1-p1-rej, br-int, "20.0.0.3/24", "40:54:00:00:00:03", \ -@@ -5349,9 +5320,6 @@ NS_CHECK_EXEC([sw0-p2-rej], [tcpdump -l -nn -i sw0-p2-rej tcp port 80 > sw0-p2-r - #Wait for tcpdump to get started before generating first packets - OVS_WAIT_UNTIL([test 1 = $(cat err | grep -c listening)]) - --OVS_WAIT_UNTIL([test "$(ip netns exec sw0-p1-rej ip a | grep aef0::3 | grep tentative)" = ""]) --OVS_WAIT_UNTIL([test "$(ip netns exec sw0-p2-rej ip a | grep aef0::4 | grep tentative)" = ""]) -- - OVS_WAIT_UNTIL([ - ip netns exec sw0-p2-rej nc -vz6 aef0::3 80 2>&1 | grep -i 'connection refused' - ]) -@@ -5878,12 +5846,10 @@ check ovn-nbctl \ - -- ls-lb-add ls lb-test - - ADD_NAMESPACES(vm1) --ADD_VETH(vm1, vm1, br-int, "4242::2/64", "00:00:00:00:00:01", "4242::1") --OVS_WAIT_UNTIL([test "$(ip netns exec vm1 ip a | grep 4242::2 | grep tentative)" = ""]) -+ADD_VETH(vm1, vm1, br-int, "4242::2/64", "00:00:00:00:00:01", "4242::1", "nodad") - - ADD_NAMESPACES(vm2) --ADD_VETH(vm2, vm2, br-int, "4242::3/64", "00:00:00:00:00:02", "4242::1") --OVS_WAIT_UNTIL([test "$(ip netns exec vm2 ip a | grep 4242::3 | grep tentative)" = ""]) -+ADD_VETH(vm2, vm2, br-int, "4242::3/64", "00:00:00:00:00:02", "4242::1", "nodad") - - # Wait for ovn-controller to catch up. - wait_for_ports_up -@@ -6145,6 +6111,10 @@ on_exit 'ovs-ofctl dump-flows br-int' - - NETNS_DAEMONIZE([alice1], [nc -l -k 80], [alice1.pid]) - NS_CHECK_EXEC([bob1], [nc -z 10.0.0.2 80], [0]) -+NS_CHECK_EXEC([bob1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) - - # Ensure conntrack entry is present. We should not try to predict - # the tunnel key for the output port, so we strip it from the labels -@@ -6152,17 +6122,19 @@ NS_CHECK_EXEC([bob1], [nc -z 10.0.0.2 80], [0]) - AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.0.1) | \ - sed -e 's/zone=[[0-9]]*/zone=/' | - sed -e 's/mark=[[0-9]]*/mark=/'], [0], [dnl -+icmp,orig=(src=172.16.0.1,dst=10.0.0.2,id=,type=8,code=0),reply=(src=10.0.0.2,dst=172.16.0.1,id=,type=0,code=0),zone=,mark=,labels=0x401020400000000 - tcp,orig=(src=172.16.0.1,dst=10.0.0.2,sport=,dport=),reply=(src=10.0.0.2,dst=172.16.0.1,sport=,dport=),zone=,mark=,labels=0x401020400000000,protoinfo=(state=) - ]) - - # Ensure datapaths show conntrack states as expected - # Like with conntrack entries, we shouldn't try to predict - # port binding tunnel keys. So omit them from expected labels. -+ovs-appctl dpctl/dump-flows | grep 'ct_state(+new-est-rpl+trk).*ct(.*label=0x401020400000000/.*)' - AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(+new-est-rpl+trk).*ct(.*label=0x401020400000000/.*)' -c], [0], [dnl --1 -+2 - ]) - AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+rpl+trk).*ct_label(0x401020400000000)' -c], [0], [dnl --1 -+2 - ]) - - # Flush conntrack entries for easier output parsing of next test. -@@ -6176,16 +6148,21 @@ ovn-nbctl set Logical_Switch_Port r2-ext \ - ovn-nbctl --wait=hv sync - - NS_CHECK_EXEC([bob1], [nc -z 10.0.0.2 80], [0]) -+NS_CHECK_EXEC([bob1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) - AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(+new-est-rpl+trk).*ct(.*label=0x1001020400000000/.*)' -c], [0], [dnl --1 -+2 - ]) - AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+rpl+trk).*ct_label(0x1001020400000000)' -c], [0], [dnl --1 -+2 - ]) - - AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 0x1001020400000000 | FORMAT_CT(172.16.0.1) | \ - sed -e 's/zone=[[0-9]]*/zone=/' | --sed -e 's/mark=[[0-9]]*/mark=/'], [0], [dnl -+sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl -+icmp,orig=(src=172.16.0.1,dst=10.0.0.2,id=,type=8,code=0),reply=(src=10.0.0.2,dst=172.16.0.1,id=,type=0,code=0),zone=,mark=,labels=0x1001020400000000 - tcp,orig=(src=172.16.0.1,dst=10.0.0.2,sport=,dport=),reply=(src=10.0.0.2,dst=172.16.0.1,sport=,dport=),zone=,mark=,labels=0x1001020400000000,protoinfo=(state=) - ]) - # Check entries in table 76 and 77 expires w/o traffic -@@ -6306,8 +6283,7 @@ NS_CHECK_EXEC([alice1], [sysctl -w net.ipv6.conf.default.router_solicitations=1] - net.ipv6.conf.default.router_solicitations = 1 - ]) - ADD_VETH(alice1, alice1, br-int, "fd01::2/64", "f0:00:00:01:02:04", \ -- "fd01::1") --OVS_WAIT_UNTIL([test "$(ip netns exec alice1 ip a | grep fd01::2 | grep tentative)" = ""]) -+ "fd01::1", "nodad") - ovn-nbctl lsp-add alice alice1 \ - -- lsp-set-addresses alice1 "f0:00:00:01:02:04 fd01::2" - # Add neighbour MAC address to avoid sending IPv6 NS messages which could -@@ -6322,8 +6298,7 @@ NS_CHECK_EXEC([bob1], [sysctl -w net.ipv6.conf.default.router_solicitations=1], - net.ipv6.conf.default.router_solicitations = 1 - ]) - ADD_VETH(bob1, bob1, br-int, "fd07::1/64", "f0:00:00:01:02:06", \ -- "fd07::2") --OVS_WAIT_UNTIL([test "$(ip netns exec bob1 ip a | grep fd07::1 | grep tentative)" = ""]) -+ "fd07::2", "nodad") - # Add neighbour MAC addresses to avoid sending IPv6 NS messages which could - # cause datapath flows to be evicted - NS_CHECK_EXEC([bob1], [ip -6 neigh add fd07::2 lladdr 00:00:02:01:02:03 dev bob1], [0]) -@@ -6339,16 +6314,20 @@ on_exit 'ovs-ofctl dump-flows br-int' - - NETNS_DAEMONIZE([alice1], [nc -6 -l -k 80], [alice1.pid]) - NS_CHECK_EXEC([bob1], [nc -6 -z fd01::2 80], [0]) -+NS_CHECK_EXEC([bob1], [ping -q -c 3 -i 0.3 -w 2 fd01::2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) - - # Ensure datapaths show conntrack states as expected - # Like with conntrack entries, we shouldn't try to predict - # port binding tunnel keys. So omit them from expected labels. - AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(+new-est-rpl+trk).*ct(.*label=0x401020400000000/.*)' -c], [0], [dnl --1 -+2 - ]) - - AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+rpl+trk).*ct_label(0x401020400000000)' -c], [0], [dnl --1 -+2 - ]) - - # Ensure conntrack entry is present. We should not try to predict -@@ -6356,7 +6335,8 @@ AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+rpl+trk).*ct_lab - # and just ensure that the known ethernet address is present. - AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd01::2) | \ - sed -e 's/zone=[[0-9]]*/zone=/' | --sed -e 's/mark=[[0-9]]*/mark=/'], [0], [dnl -+sed -e 's/mark=[[0-9]]*/mark=/' | sort], [0], [dnl -+icmpv6,orig=(src=fd07::1,dst=fd01::2,id=,type=128,code=0),reply=(src=fd01::2,dst=fd07::1,id=,type=129,code=0),zone=,mark=,labels=0x401020400000000 - tcp,orig=(src=fd07::1,dst=fd01::2,sport=,dport=),reply=(src=fd01::2,dst=fd07::1,sport=,dport=),zone=,mark=,labels=0x401020400000000,protoinfo=(state=) - ]) - -@@ -6369,17 +6349,22 @@ ovn-nbctl --wait=hv set Logical_Switch_Port r2-ext \ - type=router options:router-port=R2_ext addresses='"00:00:10:01:02:04"' - - NS_CHECK_EXEC([bob1], [nc -6 -z fd01::2 80], [0]) -+NS_CHECK_EXEC([bob1], [ping -q -c 3 -i 0.3 -w 2 fd01::2 | FORMAT_PING], \ -+[0], [dnl -+3 packets transmitted, 3 received, 0% packet loss, time 0ms -+]) - - AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(+new-est-rpl+trk).*ct(.*label=0x1001020400000000/.*)' -c], [0], [dnl --1 -+2 - ]) - AT_CHECK([ovs-appctl dpctl/dump-flows | grep 'ct_state(-new+est+rpl+trk).*ct_label(0x1001020400000000)' -c], [0], [dnl --1 -+2 - ]) - - AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 0x1001020400000000 | FORMAT_CT(fd01::2) | \ - sed -e 's/zone=[[0-9]]*/zone=/' | - sed -e 's/mark=[[0-9]]*/mark=/'], [0], [dnl -+icmpv6,orig=(src=fd07::1,dst=fd01::2,id=,type=128,code=0),reply=(src=fd01::2,dst=fd07::1,id=,type=129,code=0),zone=,mark=,labels=0x1001020400000000 - tcp,orig=(src=fd07::1,dst=fd01::2,sport=,dport=),reply=(src=fd01::2,dst=fd07::1,sport=,dport=),zone=,mark=,labels=0x1001020400000000,protoinfo=(state=) - ]) - -@@ -6513,8 +6498,6 @@ ADD_NAMESPACES(ext-foo) - ADD_VETH(ext-foo, ext-foo, br-ext, "172.16.1.100/24", "00:10:10:01:02:13", \ - "172.16.1.1") - --OVS_WAIT_UNTIL([test "$(ip netns exec ext-foo ip a | grep fe80 | grep tentative)" = ""]) -- - AT_CHECK([ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext]) - ovn-nbctl lsp-add public public1 \ - -- lsp-set-addresses public1 unknown \ -@@ -6630,6 +6613,28 @@ AT_CHECK([ovn-nbctl set Logical_Switch_Port ext options:qos_min_rate=400000]) - AT_CHECK([ovn-nbctl set Logical_Switch_Port ext options:qos_max_rate=600000]) - AT_CHECK([ovn-nbctl set Logical_Switch_Port ext options:qos_burst=6000000]) - -+OVS_WAIT_UNTIL([tc qdisc show | grep -q 'htb 1: dev ovs-public']) -+OVS_WAIT_UNTIL([tc class show dev ovs-public | \ -+ grep -q 'class htb .* rate 200Kbit ceil 300Kbit burst 375000b cburst 375000b']) -+ -+OVS_WAIT_UNTIL([tc qdisc show | grep -q 'htb 1: dev ovs-ext']) -+OVS_WAIT_UNTIL([tc class show dev ovs-ext | \ -+ grep -q 'class htb .* rate 400Kbit ceil 600Kbit burst 750000b cburst 750000b']) -+ -+# The same now with ovs db read only -+# -+AT_CHECK([ovn-nbctl remove Logical_Switch_Port ext options qos_min_rate=400000]) -+AT_CHECK([ovn-nbctl remove Logical_Switch_Port ext options qos_max_rate=600000]) -+AT_CHECK([ovn-nbctl remove Logical_Switch_Port ext options qos_burst=6000000]) -+OVS_WAIT_UNTIL([test "$(tc class show dev ovs-ext | grep 'class htb')" == ""]) -+ -+sleep_ovsdb . -+ -+AT_CHECK([ovn-nbctl set Logical_Switch_Port ext options:qos_min_rate=400000]) -+AT_CHECK([ovn-nbctl set Logical_Switch_Port ext options:qos_max_rate=600000]) -+AT_CHECK([ovn-nbctl set Logical_Switch_Port ext options:qos_burst=6000000]) -+wake_up_ovsdb . -+ - OVS_WAIT_UNTIL([tc qdisc show | grep -q 'htb 1: dev ovs-public']) - OVS_WAIT_UNTIL([tc class show dev ovs-public | \ - grep -q 'class htb .* rate 200Kbit ceil 300Kbit burst 375000b cburst 375000b']) -@@ -7348,9 +7353,9 @@ check ovn-nbctl lsp-add public public1 \ - - NS_EXEC([sw01], [tcpdump -l -n -i sw01 icmp -Q in > reject.pcap &]) - check ovn-nbctl meter-add acl-meter drop 1 pktps 0 --check ovn-nbctl --wait=hv copp-add copp0 reject acl-meter --check ovn-nbctl --wait=hv ls-copp-add copp0 sw0 --check ovn-nbctl acl-add sw0 from-lport 1002 'inport == "sw01" && ip && udp' reject -+check ovn-nbctl copp-add copp0 reject acl-meter -+check ovn-nbctl ls-copp-add copp0 sw0 -+check ovn-nbctl --wait=hv acl-add sw0 from-lport 1002 'inport == "sw01" && ip && udp' reject - - AT_CHECK([ovn-nbctl copp-list copp0], [0], [dnl - reject: acl-meter -@@ -7371,7 +7376,7 @@ rm -f reject.pcap - - # Let's update the meter - NS_EXEC([sw01], [tcpdump -l -n -i sw01 icmp -Q in > reject.pcap &]) --check ovn-nbctl --may-exist meter-add acl-meter drop 10 pktps 0 -+check ovn-nbctl --may-exist --wait=hv meter-add acl-meter drop 10 pktps 0 - ip netns exec sw01 scapy -H <<-EOF - p = IP(src="192.168.1.2", dst="192.168.1.1") / UDP(dport = 12345) / Raw(b"X"*64) - send (p, iface='sw01', loop = 0, verbose = 0, count = 40) -@@ -7402,7 +7407,7 @@ kill $(pidof tcpdump) - - NS_EXEC([server], [tcpdump -l -n -i s1 arp[[24:4]]=0xac100164 > arp.pcap &]) - check ovn-nbctl meter-add arp-meter drop 1 pktps 0 --check ovn-nbctl --wait=hv copp-add copp1 arp-resolve arp-meter -+check ovn-nbctl copp-add copp1 arp-resolve arp-meter - check ovn-nbctl --wait=hv lr-copp-add copp1 R1 - AT_CHECK([ovn-nbctl copp-list copp1], [0], [dnl - arp-resolve: arp-meter -@@ -7421,7 +7426,7 @@ OVS_WAIT_UNTIL([ - kill $(pidof tcpdump) - - check ovn-nbctl meter-add icmp-meter drop 1 pktps 0 --check ovn-nbctl --wait=hv copp-add copp2 icmp4-error icmp-meter -+check ovn-nbctl copp-add copp2 icmp4-error icmp-meter - check ovn-nbctl --wait=hv lr-copp-add copp2 R1 - AT_CHECK([ovn-nbctl copp-list copp2 |grep icmp4-error], [0], [dnl - icmp4-error: icmp-meter -@@ -7441,7 +7446,7 @@ OVS_WAIT_UNTIL([ - kill $(pidof tcpdump) - - check ovn-nbctl meter-add bfd-meter drop 1 pktps 0 --check ovn-nbctl --wait=hv copp-add copp3 bfd bfd-meter -+check ovn-nbctl copp-add copp3 bfd bfd-meter - check ovn-nbctl --wait=hv lr-copp-add copp3 R1 - AT_CHECK([ovn-nbctl copp-list copp3 |grep bfd], [0], [dnl - bfd: bfd-meter -@@ -7471,7 +7476,7 @@ kill $(pidof tcpdump) - - check ovn-nbctl set nb_global . options:svc_monitor_mac="33:33:33:33:33:33" - check ovn-nbctl meter-add svc-meter drop 1 pktps 0 --check ovn-nbctl --wait=hv copp-add copp4 svc-monitor svc-meter -+check ovn-nbctl copp-add copp4 svc-monitor svc-meter - check ovn-nbctl --wait=hv ls-copp-add copp4 sw0 - check ovn-appctl -t ovn-controller vlog/set vconn:dbg - AT_CHECK([ovn-nbctl copp-list copp4], [0], [dnl -@@ -8696,22 +8701,19 @@ check ovn-nbctl lr-nat-add lr1 snat 172.16.1.10 192.168.1.0/24 - check ovn-nbctl lr-nat-add lr1 snat 1711::10 2001::/64 - - ADD_NAMESPACES(ls1p1) --ADD_VETH(ls1p1, ls1p1, br-int, "192.168.1.1/24", "00:00:00:01:01:01", \ -- "192.168.1.254", , "2001::1/64", "2001::a") -+ADD_VETH(ls1p1, ls1p1, br-int, "2001::1/64", "00:00:00:01:01:01", \ -+ "2001::a", "nodad", "192.168.1.1/24", "192.168.1.254") - - ADD_NAMESPACES(ls1p2) --ADD_VETH(ls1p2, ls1p2, br-int, "192.168.1.2/24", "00:00:00:01:01:02", \ -- "192.168.1.254", , "2001::2/64", "2001::a") -+ADD_VETH(ls1p2, ls1p2, br-int, "2001::2/64", "00:00:00:01:01:02", \ -+ "2001::a", "nodad", "192.168.1.2/24", "192.168.1.254") - - ADD_NAMESPACES(ext1) --ADD_VETH(ext1, ext1, br0, "172.16.1.1/24", "00:ee:00:01:01:01", \ -- "172.16.1.254", , "1711::1/64", "1711::a") -+ADD_VETH(ext1, ext1, br0, "1711::1/64", "00:ee:00:01:01:01", \ -+ "1711::a", "nodad", "172.16.1.1/24", "172.16.1.254") - - check ovn-nbctl --wait=hv sync - wait_for_ports_up --OVS_WAIT_UNTIL([test "$(ip netns exec ls1p1 ip a | grep 2001::1 | grep tentative)" = ""]) --OVS_WAIT_UNTIL([test "$(ip netns exec ls1p2 ip a | grep 2002::2 | grep tentative)" = ""]) --OVS_WAIT_UNTIL([test "$(ip netns exec ext1 ip a | grep 1711::1 | grep tentative)" = ""]) - - NS_CHECK_EXEC([ls1p1], [ping -q -c 3 -i 0.3 -w 2 172.16.1.1 | FORMAT_PING], \ - [0], [dnl -@@ -9231,8 +9233,9 @@ name: 'vport4' value: '999' - NETNS_DAEMONIZE([vm1], [nc -k -l 42.42.42.2 4242], [nc-vm1.pid]) - - NETNS_DAEMONIZE([vm1], -- [tcpdump -n -i vm1 -nnleX -c6 udp and dst 42.42.42.2 and dst port 4343 > vm1.pcap 2>/dev/null], -+ [tcpdump -n -i vm1 -nnleX -c6 udp and dst 42.42.42.2 and dst port 4343 > vm1.pcap 2> vm1.pcap.stderr], - [tcpdump1.pid]) -+OVS_WAIT_UNTIL([grep "listening" vm1.pcap.stderr]) - - # Make sure connecting to the VIP works (hairpin, via ls and via lr). - NS_CHECK_EXEC([vm1], [nc 66.66.66.66 666 -z], [0], [ignore], [ignore]) -@@ -9355,16 +9358,13 @@ check ovn-nbctl --template lb-add lb-test-udp2 "^vip:^vport4" "[[4242::2]]:4343" - -- lr-lb-add rtr lb-test-udp2 - - ADD_NAMESPACES(vm1) --ADD_VETH(vm1, vm1, br-int, "4242::2/64", "00:00:00:00:00:01", "4242::1") --OVS_WAIT_UNTIL([test "$(ip netns exec vm1 ip a | grep 4242::2 | grep tentative)" = ""]) -+ADD_VETH(vm1, vm1, br-int, "4242::2/64", "00:00:00:00:00:01", "4242::1", "nodad") - - ADD_NAMESPACES(vm2) --ADD_VETH(vm2, vm2, br-int, "4242::3/64", "00:00:00:00:00:02", "4242::1") --OVS_WAIT_UNTIL([test "$(ip netns exec vm2 ip a | grep 4242::3 | grep tentative)" = ""]) -+ADD_VETH(vm2, vm2, br-int, "4242::3/64", "00:00:00:00:00:02", "4242::1", "nodad") - - ADD_NAMESPACES(vm3) --ADD_VETH(vm3, vm3, br-int, "4343::2/64", "00:00:00:00:00:03", "4343::1") --OVS_WAIT_UNTIL([test "$(ip netns exec vm3 ip a | grep 4343::2 | grep tentative)" = ""]) -+ADD_VETH(vm3, vm3, br-int, "4343::2/64", "00:00:00:00:00:03", "4343::1", "nodad") - - # Wait for ovn-controller to catch up. - wait_for_ports_up -@@ -9385,8 +9385,9 @@ name: 'vport4' value: '999' - NETNS_DAEMONIZE([vm1], [nc -k -l 4242::2 4242], [nc-vm1.pid]) - - NETNS_DAEMONIZE([vm1], -- [tcpdump -n -i vm1 -nnleX -c6 udp and dst 4242::2 and dst port 4343 > vm1.pcap 2>/dev/null], -+ [tcpdump -n -i vm1 -nnleX -c6 udp and dst 4242::2 and dst port 4343 > vm1.pcap 2> vm1.pcap.stderr], - [tcpdump1.pid]) -+OVS_WAIT_UNTIL([grep "listening" vm1.pcap.stderr]) - - # Make sure connecting to the VIP works (hairpin, via ls and via lr). - NS_CHECK_EXEC([vm1], [nc 6666::1 666 -z], [0], [ignore], [ignore]) -@@ -10825,32 +10826,28 @@ check ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \ - # Logical port 'foo1' in switch 'foo'. - ADD_NAMESPACES(foo1) - ADD_VETH(foo1, foo1, br-int, "fd11::2/64", "f0:00:00:01:02:03", \ -- "fd7b:6b4d:7b25:d22f::1") --OVS_WAIT_UNTIL([test "$(ip netns exec foo1 ip a | grep fd11::2 | grep tentative)" = ""]) -+ "fd7b:6b4d:7b25:d22f::1", "nodad") - check ovn-nbctl lsp-add foo foo1 \ - -- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd11::2" - - # Logical port 'foo2' in switch 'foo'. - ADD_NAMESPACES(foo2) - ADD_VETH(foo2, foo2, br-int, "fd11::3/64", "f0:00:00:01:02:04", \ -- "fd7b:6b4d:7b25:d22f::2") --OVS_WAIT_UNTIL([test "$(ip netns exec foo2 ip a | grep fd11::3 | grep tentative)" = ""]) -+ "fd7b:6b4d:7b25:d22f::2", "nodad") - check ovn-nbctl lsp-add foo foo2 \ - -- lsp-set-addresses foo2 "f0:00:00:01:02:04 fd11::3" - - # Logical port 'foo3' in switch 'foo'. - ADD_NAMESPACES(foo3) - ADD_VETH(foo3, foo3, br-int, "fd11::4/64", "f0:00:00:01:02:05", \ -- "fd7b:6b4d:7b25:d22d::1") --OVS_WAIT_UNTIL([test "$(ip netns exec foo3 ip a | grep fd11::4 | grep tentative)" = ""]) -+ "fd7b:6b4d:7b25:d22d::1", "nodad") - check ovn-nbctl lsp-add foo foo3 \ - -- lsp-set-addresses foo3 "f0:00:00:01:02:05 fd11::4" - - # Logical port 'bar1' in switch 'bar'. - ADD_NAMESPACES(bar1) - ADD_VETH(bar1, bar1, br-int, "fd12::2/64", "f0:00:00:01:02:06", \ --"fd7b:6b4d:7b25:d22f::3") --OVS_WAIT_UNTIL([test "$(ip netns exec foo1 ip a | grep fd12::2 | grep tentative)" = ""]) -+ "fd7b:6b4d:7b25:d22f::3", "nodad") - check ovn-nbctl lsp-add bar bar1 \ - -- lsp-set-addresses bar1 "f0:00:00:01:02:06 fd12::2" - -@@ -11686,7 +11683,7 @@ check ovn-nbctl lsp-add ls0 ls0-lr0 \ - -- lsp-set-options ls0-lr0 router-port=lr0-ls0 - - ADD_NAMESPACES(vif0) --ADD_VETH(vif0, vif0, br-int, "fd00::2/64", "00:00:00:00:00:02", "fd00::1") -+ADD_VETH(vif0, vif0, br-int, "fd00::2/64", "00:00:00:00:00:02", "fd00::1", "nodad") - OVS_WAIT_UNTIL([test "$(ip netns exec vif0 ip a | grep fe80:: | grep tentative)" = ""]) - - check ovn-nbctl set logical_router lr0 options:always_learn_from_arp_request=false -@@ -11729,3 +11726,497 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d - - AT_CLEANUP - ]) -+ -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([ct_flush on logical router load balancer]) -+AT_KEYWORDS([ct-lr-flush]) -+CHECK_CONNTRACK() -+CHECK_CONNTRACK_NAT() -+ovn_start -+OVS_TRAFFIC_VSWITCHD_START() -+ADD_BR([br-int]) -+ -+# Set external-ids in br-int needed for ovn-controller -+ovs-vsctl \ -+ -- set Open_vSwitch . external-ids:system-id=hv1 \ -+ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ -+ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ -+ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ -+ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true -+ -+start_daemon ovn-controller -+ -+check ovn-nbctl lr-add R1 -+ -+check ovn-nbctl ls-add sw0 -+check ovn-nbctl ls-add public -+ -+check ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 192.168.1.1/24 -+check ovn-nbctl lrp-add R1 rp-public 00:00:02:01:02:03 172.16.1.1/24 -+ -+check ovn-nbctl set logical_router R1 options:chassis=hv1 -+ -+check ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \ -+ type=router options:router-port=rp-sw0 \ -+ -- lsp-set-addresses sw0-rp router -+ -+check ovn-nbctl lsp-add sw0 sw0-vm \ -+ -- lsp-set-addresses sw0-vm "00:00:01:01:02:04 192.168.1.2/24" -+ -+check ovn-nbctl lsp-add public public-rp -- set Logical_Switch_Port public-rp \ -+ type=router options:router-port=rp-public \ -+ -- lsp-set-addresses public-rp router -+ -+check ovn-nbctl lsp-add public public-vm \ -+ -- lsp-set-addresses public-vm "00:00:02:01:02:04 172.16.1.2/24" -+ -+ADD_NAMESPACES(sw0-vm) -+ADD_VETH(sw0-vm, sw0-vm, br-int, "192.168.1.2/24", "00:00:01:01:02:04", \ -+ "192.168.1.1") -+ -+ADD_NAMESPACES(public-vm) -+ADD_VETH(public-vm, public-vm, br-int, "172.16.1.2/24", "00:00:02:01:02:04", \ -+ "172.16.1.1") -+ -+# Start webservers in 'server'. -+OVS_START_L7([sw0-vm], [http]) -+ -+# Create a load balancer and associate to R1 -+check ovn-nbctl lb-add lb1 172.16.1.150:80 192.168.1.2:80 \ -+ -- set load_balancer lb1 options:ct_flush="true" -+check ovn-nbctl lr-lb-add R1 lb1 -+ -+check ovn-nbctl --wait=hv sync -+ -+for i in $(seq 1 5); do -+ echo Request $i -+ NS_CHECK_EXEC([public-vm], [wget 172.16.1.150 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+done -+ -+OVS_WAIT_FOR_OUTPUT([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.1.150) | wc -l ], [0], [dnl -+1 -+]) -+ -+check ovn-nbctl --wait=hv lb-del lb1 -+ -+OVS_WAIT_FOR_OUTPUT([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.1.150) | wc -l ], [0], [dnl -+0 -+]) -+ -+check ovn-nbctl lb-add lb2 172.16.1.151:80 192.168.1.2:80 -+check ovn-nbctl lr-lb-add R1 lb2 -+ -+check ovn-nbctl --wait=hv sync -+ -+for i in $(seq 1 5); do -+ echo Request $i -+ NS_CHECK_EXEC([public-vm], [wget 172.16.1.151 -t 5 -T 1 --retry-connrefused -v -o wget$i.log]) -+done -+ -+OVS_WAIT_FOR_OUTPUT([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.1.151) | wc -l ], [0], [dnl -+1 -+]) -+ -+check ovn-nbctl --wait=hv lb-del lb2 -+ -+OVS_WAIT_FOR_OUTPUT([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(172.16.1.151) | wc -l ], [0], [dnl -+1 -+]) -+ -+OVS_APP_EXIT_AND_WAIT([ovn-controller]) -+ -+as ovn-sb -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+ -+as ovn-nb -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+ -+as northd -+OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE]) -+ -+as -+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d -+/Failed to acquire.*/d -+/connection dropped.*/d"]) -+AT_CLEANUP -+]) -+ -+AT_SETUP([load balancing in gateway router - SCTP]) -+AT_SKIP_IF([test $HAVE_SCTP = no]) -+AT_SKIP_IF([test $HAVE_NC = no]) -+AT_KEYWORDS([ovnlb sctp]) -+ -+# Make sure the SCTP kernel module is loaded. -+LOAD_MODULE([sctp]) -+ -+CHECK_CONNTRACK() -+CHECK_CONNTRACK_NAT() -+ovn_start -+OVS_TRAFFIC_VSWITCHD_START() -+ADD_BR([br-int]) -+ -+# Set external-ids in br-int needed for ovn-controller. -+ovs-vsctl \ -+ -- set Open_vSwitch . external-ids:system-id=hv1 \ -+ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ -+ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ -+ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ -+ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true -+ -+# Start the ovn-controller. -+start_daemon ovn-controller -+ -+# Logical network: -+# Two LRs - R1 and R2 that are connected to each other via LS "join" -+# in 20.0.0.0/24 network. R1 has switchess foo (192.168.1.0/24) and -+# bar (192.168.2.0/24) connected to it. R2 has alice (172.16.1.0/24) connected -+# to it. R2 is a gateway router on which we add load-balancing rules. -+# -+# foo -- R1 -- join - R2 -- alice -+# | -+# bar ---- -+ -+ovn-nbctl create Logical_Router name=R1 -+ovn-nbctl create Logical_Router name=R2 options:chassis=hv1 -+ -+ovn-nbctl ls-add foo -+ovn-nbctl ls-add bar -+ovn-nbctl ls-add alice -+ovn-nbctl ls-add join -+ -+# Connect foo to R1 -+ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24 -+ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \ -+ type=router options:router-port=foo addresses=\"00:00:01:01:02:03\" -+ -+# Connect bar to R1 -+ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 192.168.2.1/24 -+ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \ -+ type=router options:router-port=bar addresses=\"00:00:01:01:02:04\" -+ -+# Connect alice to R2 -+ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 172.16.1.1/24 -+ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \ -+ type=router options:router-port=alice addresses=\"00:00:02:01:02:03\" -+ -+# Connect R1 to join -+ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 20.0.0.1/24 -+ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \ -+ type=router options:router-port=R1_join addresses='"00:00:04:01:02:03"' -+ -+# Connect R2 to join -+ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 20.0.0.2/24 -+ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \ -+ type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"' -+ -+# Static routes. -+ovn-nbctl lr-route-add R1 172.16.1.0/24 20.0.0.2 -+ovn-nbctl lr-route-add R2 192.168.0.0/16 20.0.0.1 -+ -+# Logical port 'foo1' in switch 'foo'. -+ADD_NAMESPACES(foo1) -+ADD_VETH(foo1, foo1, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \ -+ "192.168.1.1") -+ovn-nbctl lsp-add foo foo1 \ -+-- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2" -+ -+# Logical port 'alice1' in switch 'alice'. -+ADD_NAMESPACES(alice1) -+ADD_VETH(alice1, alice1, br-int, "172.16.1.2/24", "f0:00:00:01:02:04", \ -+ "172.16.1.1") -+ovn-nbctl lsp-add alice alice1 \ -+-- lsp-set-addresses alice1 "f0:00:00:01:02:04 172.16.1.2" -+ -+# Logical port 'bar1' in switch 'bar'. -+ADD_NAMESPACES(bar1) -+ADD_VETH(bar1, bar1, br-int, "192.168.2.2/24", "f0:00:00:01:02:05", \ -+"192.168.2.1") -+ovn-nbctl lsp-add bar bar1 \ -+-- lsp-set-addresses bar1 "f0:00:00:01:02:05 192.168.2.2" -+ -+# Config OVN load-balancer with a VIP. -+uuid=`ovn-nbctl create load_balancer protocol=sctp vips:30.0.0.1="192.168.1.2,192.168.2.2"` -+ovn-nbctl set logical_router R2 load_balancer=$uuid -+ -+# Config OVN load-balancer with another VIP (this time with ports). -+ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:12345,192.168.2.2:12345"' -+ -+# Add SNAT rule to make sure that Load-balancing still works with a SNAT rule. -+ovn-nbctl -- --id=@nat create nat type="snat" logical_ip=192.168.2.2 \ -+ external_ip=30.0.0.2 -- add logical_router R2 nat @nat -+ -+# Wait for ovn-controller to catch up. -+ovn-nbctl --wait=hv sync -+OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-groups br-int | \ -+grep 'nat(dst=192.168.2.2:12345)']) -+ -+# Start webservers in 'foo1', 'bar1'. -+OVS_START_L7([foo1], [sctp]) -+OVS_START_L7([bar1], [sctp]) -+ -+on_exit "ovs-ofctl -O OpenFlow13 dump-flows br-int" -+ -+dnl Should work with the virtual IP address through NAT -+for i in `seq 1 20`; do -+ echo Request $i -+ NS_CHECK_EXEC([alice1], [nc --sctp --recv-only 30.0.0.1 12345 > client$i.log]) -+done -+ -+dnl Each server should have at least one connection. -+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | -+sed -e 's/zone=[[0-9]]*/zone=/' | -+sed 's/,protoinfo=.*$//' | uniq], [0], [dnl -+sctp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2 -+sctp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2 -+]) -+ -+dnl Test load-balancing that includes L4 ports in NAT. -+for i in `seq 1 20`; do -+ echo Request $i -+ NS_CHECK_EXEC([alice1], [nc --sctp --recv-only 30.0.0.2 8000 > clients$i.log]) -+done -+ -+dnl Each server should have at least one connection. -+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | -+sed -e 's/zone=[[0-9]]*/zone=/' | -+sed 's/,protoinfo=.*$//' | uniq], [0], [dnl -+sctp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2 -+sctp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,mark=2 -+]) -+ -+check_est_flows () { -+ n=$(ovs-ofctl dump-flows br-int table=15 | grep "+est" \ -+ | grep "ct_mark=$1" | sed -n 's/.*n_packets=\([[0-9]]\{1,\}\).*/\1/p') -+ -+ echo "n_packets=$n" -+ test -n "$n" && test "$n" != "0" -+} -+ -+OVS_WAIT_UNTIL([check_est_flows 0x2], [check established flows]) -+ -+ -+ovn-nbctl set logical_router R2 options:lb_force_snat_ip="20.0.0.2" -+ -+# Destroy the load balancer and create again. ovn-controller will -+# clear the OF flows and re add again and clears the n_packets -+# for these flows. -+ovn-nbctl destroy load_balancer $uuid -+uuid=`ovn-nbctl create load_balancer protocol=sctp vips:30.0.0.1="192.168.1.2,192.168.2.2"` -+ovn-nbctl set logical_router R2 load_balancer=$uuid -+ -+check ovs-appctl dpctl/flush-conntrack -+ -+# Config OVN load-balancer with another VIP (this time with ports). -+ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:12345,192.168.2.2:12345"' -+ -+ovn-nbctl list load_balancer -+ovn-sbctl dump-flows R2 -+OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-flows br-int table=45 | grep 'nat(src=20.0.0.2)']) -+ -+dnl Test load-balancing that includes L4 ports in NAT. -+for i in `seq 1 20`; do -+ echo Request $i -+ NS_CHECK_EXEC([alice1], [nc --sctp --recv-only 30.0.0.2 8000 > clients$i.log]) -+done -+ -+dnl Each server should have at least one connection. -+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) | -+sed -e 's/zone=[[0-9]]*/zone=/' | -+sed 's/,protoinfo=.*$//' | uniq], [0], [dnl -+sctp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.1.2,dst=172.16.1.2,sport=,dport=),zone=,mark=10 -+sctp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=,dport=),reply=(src=192.168.2.2,dst=172.16.1.2,sport=,dport=),zone=,mark=10 -+]) -+ -+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0.2) | -+sed -e 's/zone=[[0-9]]*/zone=/' | -+sed 's/,protoinfo=.*$//' | uniq], [0], [dnl -+sctp,orig=(src=172.16.1.2,dst=192.168.1.2,sport=,dport=),reply=(src=192.168.1.2,dst=20.0.0.2,sport=,dport=),zone= -+sctp,orig=(src=172.16.1.2,dst=192.168.2.2,sport=,dport=),reply=(src=192.168.2.2,dst=20.0.0.2,sport=,dport=),zone= -+]) -+ -+OVS_WAIT_UNTIL([check_est_flows 0xa], [check established flows]) -+ -+OVS_APP_EXIT_AND_WAIT([ovn-controller]) -+ -+as ovn-sb -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+ -+as ovn-nb -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+ -+as northd -+OVS_APP_EXIT_AND_WAIT([ovn-northd]) -+ -+as -+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d -+/connection dropped.*/d"]) -+AT_CLEANUP -+ -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([load balancing in gateway router - client behind LB with SNAT]) -+AT_SKIP_IF([test $HAVE_NC = no]) -+AT_KEYWORDS([lb]) -+ -+ovn_start -+OVS_TRAFFIC_VSWITCHD_START() -+ADD_BR([br-int]) -+ -+check ovs-vsctl \ -+ -- set Open_vSwitch . external-ids:system-id=hv1 \ -+ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ -+ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ -+ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ -+ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true -+ -+start_daemon ovn-controller -+ -+check ovn-nbctl lr-add lr \ -+ -- set logical_router lr options:chassis=hv1 -+check ovn-nbctl lrp-add lr lr-ls1 00:00:00:00:01:00 41.41.41.2/24 -+check ovn-nbctl lrp-add lr lr-ls2 00:00:00:00:02:00 42.42.42.2/24 -+check ovn-nbctl ls-add ls1 -+check ovn-nbctl ls-add ls2 -+ -+check ovn-nbctl lsp-add ls1 ls1-lr -+check ovn-nbctl lsp-set-addresses ls1-lr 00:00:00:00:01:00 -+check ovn-nbctl lsp-set-type ls1-lr router -+check ovn-nbctl lsp-set-options ls1-lr router-port=lr-ls1 -+check ovn-nbctl lsp-add ls1 vm1 -+check ovn-nbctl lsp-set-addresses vm1 00:00:00:00:00:01 -+ -+check ovn-nbctl lsp-add ls2 ls2-lr -+check ovn-nbctl lsp-set-addresses ls2-lr 00:00:00:00:02:00 -+check ovn-nbctl lsp-set-type ls2-lr router -+check ovn-nbctl lsp-set-options ls2-lr router-port=lr-ls2 -+check ovn-nbctl lsp-add ls2 vm2 -+check ovn-nbctl lsp-set-addresses vm2 00:00:00:00:00:02 -+ -+dnl LB using the router IP connected to vm2 as VIP. -+check ovn-nbctl lb-add lb-test 42.42.42.2:8080 41.41.41.1:8080 tcp \ -+ -- lr-lb-add lr lb-test -+ -+dnl SNAT everything coming from vm1 to the router IP (towards vm2). -+check ovn-nbctl lr-nat-add lr snat 42.42.42.2 41.41.41.1 -+ -+ADD_NAMESPACES(vm1) -+ADD_VETH(vm1, vm1, br-int, "41.41.41.1/24", "00:00:00:00:00:01", "41.41.41.2") -+ -+ADD_NAMESPACES(vm2) -+ADD_VETH(vm2, vm2, br-int, "42.42.42.1/24", "00:00:00:00:00:02", "42.42.42.2") -+ -+dnl Start a server on vm2. -+NETNS_DAEMONIZE([vm2], [nc -l -k 42.42.42.1 80], [vm2.pid]) -+ -+dnl Wait for ovn-controller to catch up. -+wait_for_ports_up -+check ovn-nbctl --wait=hv sync -+ -+dnl Test the connection originating something that uses the same source port -+dnl as the LB VIP. -+NS_CHECK_EXEC([vm1], [nc -z -p 8080 42.42.42.1 80], 0, [ignore], [ignore]) -+ -+OVS_APP_EXIT_AND_WAIT([ovn-controller]) -+ -+as ovn-sb -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+ -+as ovn-nb -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+ -+as northd -+OVS_APP_EXIT_AND_WAIT([ovn-northd]) -+ -+as -+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d -+/connection dropped.*/d"]) -+AT_CLEANUP -+]) -+ -+OVN_FOR_EACH_NORTHD([ -+AT_SETUP([load balancing affinity sessions - auto clear learnt flows]) -+AT_SKIP_IF([test $HAVE_NC = no]) -+AT_KEYWORDS([lb]) -+ -+ovn_start -+OVS_TRAFFIC_VSWITCHD_START() -+ADD_BR([br-int]) -+ -+check ovs-vsctl \ -+ -- set Open_vSwitch . external-ids:system-id=hv1 \ -+ -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ -+ -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ -+ -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ -+ -- set bridge br-int fail-mode=secure other-config:disable-in-band=true -+ -+start_daemon ovn-controller -+ -+check ovn-nbctl lr-add lr -+check ovn-nbctl lrp-add lr lr-ls 00:00:00:00:01:00 42.42.42.3/24 -+check ovn-nbctl ls-add ls -+ -+check ovn-nbctl lsp-add ls ls-lr -+check ovn-nbctl lsp-set-addresses ls-lr 00:00:00:00:01:00 -+check ovn-nbctl lsp-set-type ls-lr router -+check ovn-nbctl lsp-set-options ls-lr router-port=lr-ls -+check ovn-nbctl lsp-add ls vm1 -+check ovn-nbctl lsp-set-addresses vm1 00:00:00:00:00:01 -+check ovn-nbctl lsp-add ls vm2 -+check ovn-nbctl lsp-set-addresses vm2 00:00:00:00:00:02 -+check ovn-nbctl lb-add lb-test 43.43.43.43:80 42.42.42.1:8080,42.42.42.2:8080 tcp \ -+ -- set load_balancer lb-test options:affinity_timeout=65535 \ -+ -- ls-lb-add ls lb-test -+ -+dnl Start a server on vm1. -+ADD_NAMESPACES(vm1) -+ADD_VETH(vm1, vm1, br-int, "42.42.42.1/24", "00:00:00:00:00:01", "42.42.42.3") -+NETNS_DAEMONIZE([vm1], [nc -l -k 42.42.42.1 8080], [vm1.pid]) -+ -+dnl Start a server on vm2. -+ADD_NAMESPACES(vm2) -+ADD_VETH(vm2, vm2, br-int, "42.42.42.2/24", "00:00:00:00:00:02", "42.42.42.3") -+NETNS_DAEMONIZE([vm2], [nc -l -k 42.42.42.2 8080], [vm2.pid]) -+ -+dnl Wait for ovn-controller to catch up. -+wait_for_ports_up -+check ovn-nbctl --wait=hv sync -+ -+dnl Test the connection. -+OVS_WAIT_UNTIL([ -+ ip netns exec vm1 nc -z 43.43.43.43 80 &> /dev/null -+]) -+ -+OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows br-int | grep 'table=78, n_packets' -c) -eq 1]) -+ -+dnl Find the backend that was hit. -+backend=$(ovs-ofctl dump-flows br-int table=78 | \ -+ grep -oE 'load:0x2a2a2a0[[12]]' | sed -n 's/load:0x2a2a2a0\(.*\)/\1/p') -+ -+dnl Remove the backend that was hit. -+if [[ "$backend" == "1" ]]; then -+ check ovn-nbctl set load_balancer lb-test vip:\"43.43.43.43:80\"=\"42.42.42.2:8080\" -+else -+ check ovn-nbctl set load_balancer lb-test vip:\"43.43.43.43:80\"=\"42.42.42.1:8080\" -+fi -+check ovn-nbctl --wait=hv sync -+ -+dnl The learnt flow should also be auto deleted. -+AT_CHECK([ovs-ofctl dump-flows br-int | grep 'table=78, n_packets' -c], [1], [dnl -+0 -+]) -+ -+OVS_APP_EXIT_AND_WAIT([ovn-controller]) -+ -+as ovn-sb -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+ -+as ovn-nb -+OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -+ -+as northd -+OVS_APP_EXIT_AND_WAIT([ovn-northd]) -+ -+as -+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d -+/connection dropped.*/d"]) -+AT_CLEANUP -+]) -diff --git a/tests/test-ovn.c b/tests/test-ovn.c -index 1f1e27b51..aaf2825ed 100644 ---- a/tests/test-ovn.c -+++ b/tests/test-ovn.c -@@ -1300,11 +1300,11 @@ test_parse_actions(struct ovs_cmdl_context *ctx OVS_UNUSED) - - /* Initialize group ids. */ - struct ovn_extend_table group_table; -- ovn_extend_table_init(&group_table); -+ ovn_extend_table_init(&group_table, "group-table", OFPG_MAX); - - /* Initialize meter ids for QoS. */ - struct ovn_extend_table meter_table; -- ovn_extend_table_init(&meter_table); -+ ovn_extend_table_init(&meter_table, "meter-table", OFPM13_MAX); - - /* Initialize collector sets. */ - struct flow_collector_ids collector_ids; -diff --git a/utilities/checkpatch.py b/utilities/checkpatch.py -index 5467d604d..52d3fa845 100755 ---- a/utilities/checkpatch.py -+++ b/utilities/checkpatch.py -@@ -40,6 +40,15 @@ MAX_LINE_LEN = 79 - def open_spell_check_dict(): - import enchant - -+ try: -+ import codespell_lib -+ codespell_dir = os.path.dirname(codespell_lib.__file__) -+ codespell_file = os.path.join(codespell_dir, 'data', 'dictionary.txt') -+ if not os.path.exists(codespell_file): -+ codespell_file = '' -+ except: -+ codespell_file = '' -+ - try: - extra_keywords = ['ovs', 'vswitch', 'vswitchd', 'ovs-vswitchd', - 'netdev', 'selinux', 'ovs-ctl', 'dpctl', 'ofctl', -@@ -92,9 +101,18 @@ def open_spell_check_dict(): - 'syscall', 'lacp', 'ipf', 'skb', 'valgrind'] - - global spell_check_dict -+ - spell_check_dict = enchant.Dict("en_US") -+ -+ if codespell_file: -+ with open(codespell_file) as f: -+ for line in f.readlines(): -+ words = line.strip().split('>')[1].strip(', ').split(',') -+ for word in words: -+ spell_check_dict.add_to_session(word.strip()) -+ - for kw in extra_keywords: -- spell_check_dict.add(kw) -+ spell_check_dict.add_to_session(kw) - - return True - except: -@@ -190,6 +208,7 @@ skip_trailing_whitespace_check = False - skip_gerrit_change_id_check = False - skip_block_whitespace_check = False - skip_signoff_check = False -+skip_committer_signoff_check = False - - # Don't enforce character limit on files that include these characters in their - # name, as they may have legitimate reasons to have longer lines. -@@ -282,9 +301,13 @@ def if_and_for_end_with_bracket_check(line): - if len(line) == MAX_LINE_LEN - 1 and line[-1] == ')': - return True - -- if __regex_ends_with_bracket.search(line) is None and \ -- __regex_if_macros.match(line) is None: -- return False -+ if __regex_ends_with_bracket.search(line) is None: -+ if line.endswith("\\") and \ -+ __regex_if_macros.match(line) is not None: -+ return True -+ else: -+ return False -+ - if __regex_conditional_else_bracing.match(line) is not None: - return False - if __regex_conditional_else_bracing2.match(line) is not None: -@@ -410,9 +433,15 @@ def check_spelling(line, comment): - if not spell_check_dict or not spellcheck: - return False - -+ if line.startswith('Fixes: '): -+ return False -+ - words = filter_comments(line, True) if comment else line - words = words.replace(':', ' ').split(' ') - -+ flagged_words = [] -+ num_suggestions = 3 -+ - for word in words: - skip = False - strword = re.subn(r'\W+', '', word)[0].replace(',', '') -@@ -437,9 +466,15 @@ def check_spelling(line, comment): - skip = True - - if not skip: -- print_warning("Check for spelling mistakes (e.g. \"%s\")" -- % strword) -- return True -+ flagged_words.append(strword) -+ -+ if len(flagged_words) > 0: -+ for mistake in flagged_words: -+ print_warning("Possible misspelled word: \"%s\"" % mistake) -+ print("Did you mean: ", -+ spell_check_dict.suggest(mistake)[:num_suggestions]) -+ -+ return True - - return False - -@@ -780,6 +815,36 @@ def run_file_checks(text): - check['check'](text) - - -+def run_subject_checks(subject, spellcheck=False): -+ warnings = False -+ -+ if spellcheck and check_spelling(subject, False): -+ warnings = True -+ -+ summary = subject[subject.rindex(': ') + 2:] -+ area_summary = subject[subject.index(': ') + 2:] -+ area_summary_len = len(area_summary) -+ if area_summary_len > 70: -+ print_warning("The subject, ': ', is over 70 " -+ "characters, i.e., %u." % area_summary_len) -+ warnings = True -+ -+ if summary[0].isalpha() and summary[0].islower(): -+ print_warning( -+ "The subject summary should start with a capital.") -+ warnings = True -+ -+ if subject[-1] not in [".", "?", "!"]: -+ print_warning( -+ "The subject summary should end with a dot.") -+ warnings = True -+ -+ if warnings: -+ print(subject) -+ -+ return warnings -+ -+ - def ovs_checkpatch_parse(text, filename, author=None, committer=None): - global print_file_name, total_line, checking_file, \ - empty_return_check_state -@@ -800,6 +865,7 @@ def ovs_checkpatch_parse(text, filename, author=None, committer=None): - r'^@@ ([0-9-+]+),([0-9-+]+) ([0-9-+]+),([0-9-+]+) @@') - is_author = re.compile(r'^(Author|From): (.*)$', re.I | re.M | re.S) - is_committer = re.compile(r'^(Commit: )(.*)$', re.I | re.M | re.S) -+ is_subject = re.compile(r'^(Subject: )(.*)$', re.I | re.M | re.S) - is_signature = re.compile(r'^(Signed-off-by: )(.*)$', - re.I | re.M | re.S) - is_co_author = re.compile(r'^(Co-authored-by: )(.*)$', -@@ -874,7 +940,8 @@ def ovs_checkpatch_parse(text, filename, author=None, committer=None): - break - if (committer - and author != committer -- and committer not in signatures): -+ and committer not in signatures -+ and not skip_committer_signoff_check): - print_error("Committer %s needs to sign off." - % committer) - -@@ -899,6 +966,8 @@ def ovs_checkpatch_parse(text, filename, author=None, committer=None): - committer = is_committer.match(line).group(2) - elif is_author.match(line): - author = is_author.match(line).group(2) -+ elif is_subject.match(line): -+ run_subject_checks(line, spellcheck) - elif is_signature.match(line): - m = is_signature.match(line) - signatures.append(m.group(2)) -@@ -990,7 +1059,8 @@ Check options: - -S|--spellcheck Check C comments and commit-message for possible - spelling mistakes - -t|--skip-trailing-whitespace Skips the trailing whitespace test -- --skip-gerrit-change-id Skips the gerrit change id test""" -+ --skip-gerrit-change-id Skips the gerrit change id test -+ --skip-committer-signoff Skips the committer sign-off test""" - % sys.argv[0]) - - -@@ -1017,6 +1087,19 @@ def ovs_checkpatch_file(filename): - result = ovs_checkpatch_parse(part.get_payload(decode=False), filename, - mail.get('Author', mail['From']), - mail['Commit']) -+ -+ if not mail['Subject'] or not mail['Subject'].strip(): -+ if mail['Subject']: -+ mail.replace_header('Subject', sys.argv[-1]) -+ else: -+ mail.add_header('Subject', sys.argv[-1]) -+ -+ print("Subject missing! Your provisional subject is", -+ mail['Subject']) -+ -+ if run_subject_checks('Subject: ' + mail['Subject'], spellcheck): -+ result = True -+ - ovs_checkpatch_print_result() - return result - -@@ -1048,6 +1131,7 @@ if __name__ == '__main__': - "skip-signoff-lines", - "skip-trailing-whitespace", - "skip-gerrit-change-id", -+ "skip-committer-signoff", - "spellcheck", - "quiet"]) - except: -@@ -1068,6 +1152,8 @@ if __name__ == '__main__': - skip_trailing_whitespace_check = True - elif o in ("--skip-gerrit-change-id"): - skip_gerrit_change_id_check = True -+ elif o in ("--skip-committer-signoff"): -+ skip_committer_signoff_check = True - elif o in ("-f", "--check-file"): - checking_file = True - elif o in ("-S", "--spellcheck"): -diff --git a/utilities/containers/fedora/Dockerfile b/utilities/containers/fedora/Dockerfile -index 4058d7f5b..c11ea37b7 100755 ---- a/utilities/containers/fedora/Dockerfile -+++ b/utilities/containers/fedora/Dockerfile -@@ -1,4 +1,4 @@ --FROM quay.io/fedora/fedora:latest -+FROM quay.io/fedora/fedora:38 - - ARG CONTAINERS_PATH - -diff --git a/utilities/containers/py-requirements.txt b/utilities/containers/py-requirements.txt -index 0d90765c9..aac98443b 100644 ---- a/utilities/containers/py-requirements.txt -+++ b/utilities/containers/py-requirements.txt -@@ -1,5 +1,4 @@ --flake8 --hacking>=3.0 -+flake8==5.0.4 - scapy - sphinx - setuptools -diff --git a/utilities/containers/ubuntu/Dockerfile b/utilities/containers/ubuntu/Dockerfile -index 5d5bedbd9..3c7fe7775 100755 ---- a/utilities/containers/ubuntu/Dockerfile -+++ b/utilities/containers/ubuntu/Dockerfile -@@ -1,4 +1,4 @@ --FROM registry.hub.docker.com/library/ubuntu:latest -+FROM registry.hub.docker.com/library/ubuntu:22.04 - - ARG CONTAINERS_PATH - -diff --git a/utilities/ovn-ctl.8.xml b/utilities/ovn-ctl.8.xml -index 82804096f..01f4aa26b 100644 ---- a/utilities/ovn-ctl.8.xml -+++ b/utilities/ovn-ctl.8.xml -@@ -136,12 +136,14 @@ -

      --db-nb-cluster-remote-addr=IP ADDRESS

      -

      --db-nb-cluster-remote-port=PORT NUMBER

      -

      --db-nb-cluster-remote-proto=PROTO (tcp/ssl)

      -+

      --db-nb-election-timer=Timeout in milliseconds

      -

      --db-sb-cluster-local-addr=IP ADDRESS

      -

      --db-sb-cluster-local-port=PORT NUMBER

      -

      --db-sb-cluster-local-proto=PROTO (tcp/ssl)

      -

      --db-sb-cluster-remote-addr=IP ADDRESS

      -

      --db-sb-cluster-remote-port=PORT NUMBER

      -

      --db-sb-cluster-remote-proto=PROTO (tcp/ssl)

      -+

      --db-sb-election-timer=Timeout in milliseconds

      -

      --db-ic-nb-cluster-local-addr=IP ADDRESS

      -

      --db-ic-nb-cluster-local-port=PORT NUMBER

      -

      --db-ic-nb-cluster-local-proto=PROTO (tcp/ssl)

      -diff --git a/utilities/ovn-dbctl.c b/utilities/ovn-dbctl.c -index 2e9348c47..92be27b2c 100644 ---- a/utilities/ovn-dbctl.c -+++ b/utilities/ovn-dbctl.c -@@ -610,6 +610,14 @@ apply_options_direct(const struct ovn_dbctl_options *dbctl_options, - ssl_ca_cert_file = optarg; - break; - -+ case OPT_SSL_PROTOCOLS: -+ stream_ssl_set_protocols(optarg); -+ break; -+ -+ case OPT_SSL_CIPHERS: -+ stream_ssl_set_ciphers(optarg); -+ break; -+ - case OPT_BOOTSTRAP_CA_CERT: - stream_ssl_set_ca_cert_file(po->arg, true); - break; -diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c -index 444fbd2fe..821ad44dd 100644 ---- a/utilities/ovn-nbctl.c -+++ b/utilities/ovn-nbctl.c -@@ -4693,6 +4693,7 @@ static void - nexthop = normalize_prefix_str(ctx->argv[3]); - if (!nexthop) { - ctl_error(ctx, "bad nexthop argument: %s", ctx->argv[3]); -+ free(prefix); - return; - } - } -diff --git a/utilities/ovn-sbctl.c b/utilities/ovn-sbctl.c -index 3948cae3f..f1f8c2b42 100644 ---- a/utilities/ovn-sbctl.c -+++ b/utilities/ovn-sbctl.c -@@ -396,7 +396,9 @@ pre_get_info(struct ctl_context *ctx) - ovsdb_idl_add_column(ctx->idl, &sbrec_mac_binding_col_mac); - - ovsdb_idl_add_column(ctx->idl, &sbrec_load_balancer_col_datapaths); -+ /* datapath_group column is deprecated. */ - ovsdb_idl_add_column(ctx->idl, &sbrec_load_balancer_col_datapath_group); -+ ovsdb_idl_add_column(ctx->idl, &sbrec_load_balancer_col_ls_datapath_group); - ovsdb_idl_add_column(ctx->idl, &sbrec_load_balancer_col_vips); - ovsdb_idl_add_column(ctx->idl, &sbrec_load_balancer_col_name); - ovsdb_idl_add_column(ctx->idl, &sbrec_load_balancer_col_protocol); -@@ -932,10 +934,15 @@ cmd_lflow_list_load_balancers(struct ctl_context *ctx, struct vconn *vconn, - break; - } - } -+ /* datapath_group column is deprecated. */ - if (lb->datapath_group && !dp_found) { - dp_found = datapath_group_contains_datapath(lb->datapath_group, - datapath); - } -+ if (lb->ls_datapath_group && !dp_found) { -+ dp_found = datapath_group_contains_datapath( -+ lb->ls_datapath_group, datapath); -+ } - if (!dp_found) { - continue; - } -@@ -954,11 +961,17 @@ cmd_lflow_list_load_balancers(struct ctl_context *ctx, struct vconn *vconn, - print_vflow_datapath_name(lb->datapaths[i], true, - &ctx->output); - } -+ /* datapath_group column is deprecated. */ - for (size_t i = 0; lb->datapath_group - && i < lb->datapath_group->n_datapaths; i++) { - print_vflow_datapath_name(lb->datapath_group->datapaths[i], - true, &ctx->output); - } -+ for (size_t i = 0; lb->ls_datapath_group -+ && i < lb->ls_datapath_group->n_datapaths; i++) { -+ print_vflow_datapath_name(lb->ls_datapath_group->datapaths[i], -+ true, &ctx->output); -+ } - } - - ds_put_cstr(&ctx->output, "\n vips:\n"); -diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c -index 0b86eae7b..e0f1c3ec9 100644 ---- a/utilities/ovn-trace.c -+++ b/utilities/ovn-trace.c -@@ -983,6 +983,7 @@ parse_lflow_for_datapath(const struct sbrec_logical_flow *sblf, - if (error) { - VLOG_WARN("%s: parsing expression failed (%s)", - sblf->match, error); -+ expr_destroy(match); - free(error); - return; - } -@@ -2462,7 +2463,7 @@ execute_ct_nat(const struct ovnact_ct_nat *ct_nat, - } - - static void --execute_ct_commit_nat(const struct ovnact_ct_nat *ct_nat, -+execute_ct_commit_nat(const struct ovnact_ct_commit_nat *ct_nat, - const struct ovntrace_datapath *dp, struct flow *uflow, - enum ovnact_pipeline pipeline, struct ovs_list *super) - { diff --git a/SPECS/ovn23.09.spec b/SPECS/ovn23.09.spec index 608dc84..a3aadf5 100644 --- a/SPECS/ovn23.09.spec +++ b/SPECS/ovn23.09.spec @@ -50,8 +50,8 @@ Name: %{pkgname} Summary: Open Virtual Network support Group: System Environment/Daemons URL: http://www.ovn.org/ -Version: 23.09.0 -Release: 136%{?commit0:.%{date}git%{shortcommit0}}%{?dist} +Version: 23.09.3 +Release: 5%{?commit0:.%{date}git%{shortcommit0}}%{?dist} Provides: openvswitch%{pkgver}-ovn-common = %{?epoch:%{epoch}:}%{version}-%{release} Obsoletes: openvswitch%{pkgver}-ovn-common < 2.11.0-1 @@ -59,7 +59,7 @@ Obsoletes: openvswitch%{pkgver}-ovn-common < 2.11.0-1 # lib/sflow*.[ch] files are SISSL License: ASL 2.0 and LGPLv2+ and SISSL -%define ovncommit 56d5cf6ccf4a7b034b3d0c009fbca7c509f2f42a +%define ovncommit fbdc94d4309f28ad59e41025ff42945478dd12cc # Always pull an upstream release, since this is what we rebase to. Source: https://github.com/ovn-org/ovn/archive/%{ovncommit}.tar.gz#/ovn-%{version}.tar.gz @@ -530,535 +530,11 @@ fi %{_unitdir}/ovn-controller-vtep.service %changelog -* Mon Mar 11 2024 Frode Nordahl - 23.09.0-136 -- controller: Set check_tnl_key for BFD on tunnel ifaces. -[Upstream: c966c35f1b1cd8c5351ccac3051843fbf765c2ae] +* Tue Mar 12 2024 Ilya Maximets - 23.09.3-5 +- github: Reduce ASLR entropy to be compatible with asan in llvm 14. +[Upstream: 835b43811dfcf469da3123911240cc953b52bac3] -* Fri Mar 08 2024 Dumitru Ceara - 23.09.0-135 -- tests: Skip EDNS test if the scapy version doesn't support it. -[Upstream: 7af89a5e50a4ba75a3ea5c393499f1e0fa0a6abb] - -* Wed Mar 06 2024 Dumitru Ceara - 23.09.0-134 -- northd: Don't skip the unSNAT stage for traffic towards VIPs. -[Upstream: 094b1217345a8ae5935fdd4dfec4949f46197377] - -* Fri Mar 01 2024 Mark Michelson - 23.09.0-133 -- Prepare for 23.09.3. -[Upstream: 7bd52d7a25f2ddad0be25a5e54a3eb63d98a19d8] - -* Fri Mar 01 2024 Mark Michelson - 23.09.0-132 -- Set release date for 23.09.2. -[Upstream: 04b23938302ad54f453f622a4b0c2fa5e27d3e41] - -* Thu Feb 29 2024 Ilya Maximets - 23.09.0-131 -- northd: Don't create fair Sb meters for ACLs with logging disabled. -[Upstream: 215d53ea1436f03ab26a1a65df0824b319e6a4c3] - -* Wed Feb 28 2024 Mohammad Heib - 23.09.0-130 -- ci: Update crun in GitHub actions runner. -[Upstream: 5bf1773c90ef7b61a85946027a987184e8d74fa0] - -* Wed Feb 28 2024 Ales Musil - 23.09.0-129 -- ci: Update crun in Cirrus CI cloud image. -[Upstream: afa3da7677ed4d484612b820d8f09642d5821bd4] - -* Tue Feb 27 2024 Ilya Maximets - 23.09.0-128 -- controller: ofctrl: Use index for meter lookups. -[Upstream: 683fb6dd2fc3c2ab025b1dd87ba2883e40d6d775] - -* Mon Feb 19 2024 Xavier Simonart - 23.09.0-127 -- tests: Fix "router port type update and then ...". -[Upstream: c463d1de1a0c2cd368a4809f0d9eda9792b79851] - -* Mon Feb 19 2024 Xavier Simonart - 23.09.0-126 -- tests: Fix "ovn-controller - Chassis other_config". -[Upstream: cbd4f2fcd0223a96c739dd07eded753f8f9b2a30] - -* Mon Feb 19 2024 Xavier Simonart - 23.09.0-125 -- tests: Fix "ofctrl wait before clearing flows". -[Upstream: 81486b62bcac0d081ca907533ae34d826605b485] - -* Mon Feb 19 2024 Xavier Simonart - 23.09.0-124 -- tests: Fix flaky "ovn-controller-vtep - binding 1". -[Upstream: 48a08a447340b095e8472d40aaaac5156320b4c1] - -* Mon Feb 19 2024 Xavier Simonart - 23.09.0-123 -- tests: Fix flaky "options:requested-chassis ...". -[Upstream: a088df5aa75a7207ccdd751d2167e1536113737f] - -* Mon Feb 19 2024 Xavier Simonart - 23.09.0-122 -- tests: Fix typos in tests. -[Upstream: 0a5726652b202add51d1dc8b6557268673e6cc51] - -* Mon Feb 19 2024 Xavier Simonart - 23.09.0-121 -- tests: Have tests fail when adding veth peer fails. -[Upstream: 609a943e33c734d368f2019e7d3b41e31bb31d6f] - -* Mon Feb 12 2024 Dumitru Ceara - 23.09.0-120 -- pinctrl: dns: Ignore additional records. -[Upstream: 511f5a214226be84ae3b9434ffcab973e37295eb] - -* Mon Feb 12 2024 Roberto Bartzen Acosta - 23.09.0-119 -- ovn-ic: Fix global blacklist filter for IPv6 addresses. -[Upstream: 27d23712260b9faba23018ce973010743e30ccf7] - -* Mon Feb 12 2024 Xavier Simonart - 23.09.0-118 -- tests: Fix macro OVN_CHECK_PACKETS_CONTAIN. -[Upstream: 28b0eddff68c5a64b80071a9a27cb79e3fac792a] - -* Fri Feb 09 2024 Mark Michelson - 23.09.0-117 -- features.c: Always wait on the rconn. -[Upstream: c0c9e507470439c3220b99c361f71e0cff3406fc] - -* Fri Feb 09 2024 Ales Musil - 23.09.0-116 -- ci: Bump CirrusCI Ubuntu image version -[Upstream: 41e7f01872dae61b9ffcc1d3871865313ff90619] - -* Fri Feb 09 2024 Nobuhiro MIKI - 23.09.0-115 -- Documentation: Fix broken links in ovn-sandbox.rst. -[Upstream: 99d22a176f45971516803129f08c7a37a50bc4a1] - -* Fri Feb 09 2024 Mark Michelson - 23.09.0-114 -- ovn-sb.xml: Remove IPv4-only restriction from Service Monitors. -[Upstream: 97fca0f846bf6839144fc04fed6f0873198b4f89] - -* Fri Feb 09 2024 Ilya Maximets - 23.09.0-113 -- github: Update versions of action dependencies (Node.js 20). -[Upstream: 2981936b61e0e0694c16df979b986dd1cb60b147] - -* Thu Feb 08 2024 Ales Musil - 23.09.0-112 -- northd: Remove the protocol match from ECMP symmetric reply flows. -[Upstream: a36f2955be67a6581e81fb3ae27de825e0046b52] - -* Thu Feb 08 2024 Ales Musil - 23.09.0-111 -- northd: Explicitly handle SNAT for ICMP need frag. -[Upstream: 6a4c412f43d5f1c076fac3784a4ffeb8a3861436] - -* Thu Feb 08 2024 Ales Musil - 23.09.0-110 -- actions: Adjust the ct_commit_nat action. -[Upstream: 069842478601c0b01b0cc3117637e5a00344fcb6] - -* Tue Jan 30 2024 Dumitru Ceara - 23.09.0-109 -- ovs: Bump submodule to tip of OVS branch-3.2. -[Upstream: f224c6e5f69c099ddb008f99dba2e19a902a612f] - -* Tue Jan 30 2024 Dumitru Ceara - 23.09.0-108 -- actions: Use random port selection for SNAT with external_port_range. -[Upstream: 7ee483a45df19e11e26487e64a93940e0de64b9a] - -* Tue Jan 30 2024 Mohammad Heib - 23.09.0-107 -- ovn-ic: Handle NB:name updates properly. -[Upstream: 0e684ec206e8979694912ad1037145ccd0d0b7dc] - -* Thu Jan 25 2024 Ales Musil - 23.09.0-106 -- northd: Make sure that affinity flows match on VIP. -[Upstream: 859e8d917408d50272c910f78ac44ab8a593aa13] - -* Wed Jan 24 2024 Aliasgar Ginwala - 23.09.0-105 -- Fix segfault due to ssl-ciphers. -[Upstream: d39e7c0068ecc719a3d6154e2078d6d9a3435fc9] - -* Wed Jan 24 2024 Lorenzo Bianconi - 23.09.0-104 -- ovn: Add tunnel PMTUD support. (#2241711) -[Upstream: 6d2f9d60760a793c15ca7423b24ff586b653fc76] - -* Tue Jan 23 2024 Xavier Simonart - 23.09.0-103 -- controller: fixed potential segfault when changing tunnel_key and deleting ls. -[Upstream: 120075357a624293d52a1905c47a1bd249d2157c] - -* Fri Jan 19 2024 Ales Musil - 23.09.0-102 -- northd: Use proper field for lookup_nd -[Upstream: 8e25c1c37aa3301f69bc89ee49ffaef5aa2f76fd] - -* Wed Jan 17 2024 Dumitru Ceara - 23.09.0-101 -- checkpatch.py: Port checkpatch related changes from the OVS repo. -[Upstream: bf334c65e1ead50013880049564d445919aee61f] - -* Fri Jan 12 2024 Dumitru Ceara - 23.09.0-100 -- actions: Make sure affinity learnt flows are auto deleted. -[Upstream: 6ce267af7124a93306d8b5bf4944379536ecd264] - -* Thu Jan 11 2024 Mark Michelson - 23.09.0-99 -- pinctrl: Directly retrieve desired port_binding MAC. -[Upstream: f85f5e3929c916985c7dfc0fe0f0433347d8bfae] - -* Tue Jan 09 2024 Lorenzo Bianconi - 23.09.0-98 -- test: add dedicated test for garp-max-timeout -[Upstream: 28fef02db946ba8113a2752e1abf61d8df5797e3] - -* Tue Jan 09 2024 Ales Musil - 23.09.0-97 -- treewide: Fix small memory leaks reported by static analysis -[Upstream: 0d5e6d65db19845aede9198d8e164d934a5f189e] - -* Tue Jan 09 2024 Ales Musil - 23.09.0-96 -- Documentation: Add note about pinning the container after release -[Upstream: 1a70f3f171c032c2329bb66f2e62d233ce19a494] - -* Tue Jan 09 2024 Ales Musil - 23.09.0-95 -- ci: Cover more container posibilities -[Upstream: 639aff0896527f9c48c56d6dfb3fdce84403b6dd] - -* Tue Jan 09 2024 Ales Musil - 23.09.0-94 -- ci: Build container image before very job -[Upstream: ca0f17758559ed836dfa0220e472ea99438cefb8] - -* Tue Jan 09 2024 Dumitru Ceara - 23.09.0-93 -- ovs: Bump submodule to include IDL "spurious delete" fix. -[Upstream: 9c97cdcd757ce356a85b3e6dde7eb19776fe4c38] - -* Wed Jan 03 2024 Jacob Tanenbaum - 23.09.0-92 -- Correct ethtype referencing incorrect values -[Upstream: e9863e57320d24f8fb0d02436834f795ba58ce48] - -* Mon Dec 18 2023 Numan Siddique - 23.09.0-91 -- Revert "ovn: add geneve PMTUD support" -[Upstream: ed4e4a94ba44f5d5be5148ee82f336cab3adc7ec] - -* Mon Dec 18 2023 Daniel Ding - 23.09.0-90 -- northd: forward arp request to lrp snat on. -[Upstream: 20ea3b63fb3a2fce2c9e273bfbdcb4d8399b8091] - -* Wed Dec 13 2023 Xavier Simonart - 23.09.0-89 -- northd: fix missing port up when deleting and adding back an lsp -[Upstream: 8cabb443ae88dded5cd1800bdcea5c5760954d25] - -* Fri Dec 08 2023 Dumitru Ceara - 23.09.0-88 -- ovn-macros: Make sure stopped daemons continue before the test ends. -[Upstream: e54ec661ef67cd93d1a72de907b37fab522bc2f9] - -* Thu Dec 07 2023 Dumitru Ceara - 23.09.0-87 -- system-test: Fix tcpdump usage in LB template tests. -[Upstream: 5141c9d4c7c861f6a65a711e59a4e64ae7d2fcdb] - -* Thu Dec 07 2023 Eelco Chaudron - 23.09.0-86 -- tests: Move SCTP test from kernel only to general OVN system tests. -[Upstream: 49d33629595a9c7fc44d7ac86926c83e475b322d] - -* Thu Dec 07 2023 Eelco Chaudron - 23.09.0-85 -- tests: Remove 'protoinfo' from the conntrack entries for SCTP tests. -[Upstream: d87ffbe44d5b5c3f143c1e38e868f9db636b4565] - -* Thu Dec 07 2023 Dumitru Ceara - 23.09.0-84 -- northd: Skip transient IDL records. -[Upstream: 44a40011f0b7f465c1eb60c9016bd56e09d7e538] - -* Thu Dec 07 2023 Ales Musil - 23.09.0-83 -- system-tests: Consolidate wait condition in CoPP test -[Upstream: ba7a45bde1de25868e0b16d8e58e6d523e2034ab] - -* Thu Dec 07 2023 Dumitru Ceara - 23.09.0-82 -- pinctrl: Fix up comments about sending RST packets for healthcheck. -[Upstream: 4ef375edc8bee094f24b9e649dc01ce3edd2034b] - -* Mon Dec 04 2023 Lorenzo Bianconi - 23.09.0-81 -- ovn: add geneve PMTUD support (#2241711) -[Upstream: e42ca82fb92cd69bbfd4da72b3c22bc57fc1ecd0] - -* Mon Dec 04 2023 Ihar Hrachyshka - 23.09.0-80 -- fmt_pkt: make sure scapy-server is started once -[Upstream: b788911812171ee5d9c51806b1e287be910164c9] - -* Mon Dec 04 2023 Ihar Hrachyshka - 23.09.0-79 -- fmt_pkt: improve scapy-server logging -[Upstream: 820e11754bff7b7029abf8bd8f166c169bdd8d04] - -* Mon Dec 04 2023 Ihar Hrachyshka - 23.09.0-78 -- fmt_pkt: use -S check to wait for scapy sock file -[Upstream: 2d710c3b1d9444a49f80db6058462e7d33253644] - -* Mon Dec 04 2023 Ihar Hrachyshka - 23.09.0-77 -- fmt_pkt: don't subshell when calling ovs-appctl -[Upstream: fc311bb6d6108d49b356d9c785f6d47e7dc8faff] - -* Mon Dec 04 2023 Xavier Simonart - 23.09.0-76 -- controller: fix group_table and meter_table allocation -[Upstream: acc63727d14ff7e9f447ed90115f74235f968499] - -* Fri Dec 01 2023 Mark Michelson - 23.09.0-75 -- Prepare for 23.09.2. -[Upstream: 8a000cc863773030828a4cda2167840f08c4a65c] - -* Fri Dec 01 2023 Mark Michelson - 23.09.0-74 -- Set release date for 23.09.1. -[Upstream: 0afd4e59e95b5f8c7b56760e91269786b0e0e52a] - -* Mon Nov 27 2023 Dumitru Ceara - 23.09.0-73 -- northd: Add missing stopwatch initialization. -[Upstream: 7fd87c5d0b1492c14d90faec4af4069496ae3609] - -* Fri Nov 24 2023 Xavier Simonart - 23.09.0-72 -- controller: avoid extra flows if localnet_learn_fdb is disabled -[Upstream: b2f839849c36c058f940c417dc29e26165a1d30e] - -* Fri Nov 24 2023 Xavier Simonart - 23.09.0-71 -- controller: FDB entries for localnet should not overwrite entries for vifs (#2242830) -[Upstream: 33b0117598b23b8c0877e482ee350283a147bb5f] - -* Mon Nov 20 2023 Ales Musil - 23.09.0-70 -- controller: Disable inactivity probe for statctrl -[Upstream: bbd07439b9a8cd6db901bffcac7ac17f58e33a07] - -* Mon Nov 20 2023 Evgenii Kovalev - 23.09.0-69 -- pinctrl: reset success and failures n_count regardless of svc state -[Upstream: 617b84d7dd2ce3501b49e988e1ba06e86889c9bd] - -* Mon Nov 20 2023 Evgenii Kovalev - 23.09.0-68 -- pinctrl: send RST instead of RST_ACK bit for lb hc -[Upstream: beb26027cf26271c7cd780869b540737c7916e99] - -* Mon Nov 20 2023 Dumitru Ceara - 23.09.0-67 -- controller: Don't artificially limit group and meter IDs to 16bit. -[Upstream: e9e716ad531e34766d2f02783ac08955096bf636] - -* Fri Nov 17 2023 Xavier Simonart - 23.09.0-66 -- tests: fixed race_condition with max_prefix -[Upstream: d257d800e41388bd2a387e0b6d5a0e41c2e8d8f1] - -* Fri Nov 17 2023 Xavier Simonart - 23.09.0-65 -- tests: have CHECK_NO_CHANGE_AFTER_RECOMPUTE potentially wait for ports up -[Upstream: dab54b81c7ee767943163f2aaaa27b2c4b367964] - -* Fri Nov 17 2023 Xavier Simonart - 23.09.0-64 -- tests: fixed "ovn-nbctl - daemon retry connection" -[Upstream: d2e0acb2a6aa510282da5e04036ec5258454c351] - -* Fri Nov 17 2023 Xavier Simonart - 23.09.0-63 -- tests: fixed system test "LR with SNAT fragmentation needed for external server". -[Upstream: 0bb6ba908421825428ec904d5316ae13090adbbf] - -* Fri Nov 17 2023 Xavier Simonart - 23.09.0-62 -- tests: fixed "interconnection - static multicast" and "- IGMP/MLD multicast" -[Upstream: 810d83e77ce3398bc94469404d85a01eb63e40bd] - -* Fri Nov 17 2023 martin.kalcok@canonical.com - 23.09.0-61 -- ovn-ctl man: Add election timer config to manpage -[Upstream: 25d4b6855f6ce3795314e9439716f775994c7f4d] - -* Fri Nov 17 2023 Xavier Simonart - 23.09.0-60 -- Fix flows not removed in ha migration -[Upstream: 5375cdd96eaf8e527e5afea402f279990398710c] - -* Fri Nov 17 2023 Xavier Simonart - 23.09.0-59 -- binding: handle pb->chassis and pb->up from if-status module -[Upstream: 619abe5c5e18f417fe20b252ca41b70e644466e0] - -* Fri Nov 17 2023 Xavier Simonart - 23.09.0-58 -- binding: slight refactor if no local binding in consider_iface_release -[Upstream: d039b4332b9ea739bdf6b2efc9f5f3e422fe9a42] - -* Fri Nov 17 2023 Xavier Simonart - 23.09.0-57 -- controller: have I+P assigning ct_zones for l3gateway ports -[Upstream: f5d01be7f1337bdc7885dd45592aa3b376467790] - -* Fri Nov 17 2023 Xavier Simonart - 23.09.0-56 -- tests: fixed another set of flaky ovn-ic tests -[Upstream: 650bffdbe0562dc364faaef51f51f99e82cccc56] - -* Fri Nov 17 2023 Xavier Simonart - 23.09.0-55 -- tests: wait for all flows to be installed before sending packets -[Upstream: b3d03b94178bee2479d6f66ffa34255a7feb79eb] - -* Fri Nov 17 2023 Xavier Simonart - 23.09.0-54 -- tests: fixed "ipsec -- basic configuration" -[Upstream: ac3ece28ca04cb74b21c80e2bd73767e29cca9a3] - -* Fri Nov 17 2023 Xavier Simonart - 23.09.0-53 -- tests: fixed "LSP incremental processing" -[Upstream: fcbc0ae1c66e31c38ad9d5e099237e7446958035] - -* Fri Nov 17 2023 Xavier Simonart - 23.09.0-52 -- tests: do not start backup-northd by default -[Upstream: 54fae8cbb5db827da95a2a52ff28f29e6c7740fe] - -* Fri Nov 17 2023 Xavier Simonart - 23.09.0-51 -- tests: fixed multiple tests not properly waiting for packets to be received -[Upstream: a1422144228bb9924dbc75782734a09c6ecfa534] - -* Fri Nov 17 2023 Dumitru Ceara - 23.09.0-50 -- ci: Pin Python, Fedora and Ubuntu runner versions. -[Upstream: 627955eb79c2cd374853319c1d271c2fd1aeac37] - -* Thu Nov 16 2023 Dumitru Ceara - 23.09.0-49 -- ovs: Bump submodule to include E721 fixes. -[Upstream: 1fa7628db4155d3a39d55fe61d8d19fa7d3030af] - -* Thu Nov 16 2023 Dumitru Ceara - 23.09.0-48 -- tests: Remove broken "feature inactivity probe" test. -[Upstream: 5044376da0a1c14d1ccc4b41dfdbae14e74746b2] - -* Wed Nov 15 2023 Ilya Maximets - 23.09.0-47 -- readthedocs: Add the configuration file. -[Upstream: 84c93511ce9a612b9a815cc1403b4841cc2e4c58] - -* Wed Nov 15 2023 Ilya Maximets - 23.09.0-46 -- Documentation: Use theme from Read The Docs. -[Upstream: 39236dc3151baa3ace58c3ecd62ba0384b4c7a05] - -* Wed Nov 15 2023 Dumitru Ceara - 23.09.0-45 -- ovs: Bump submodule to v3.2.1. -[Upstream: 74172ed481f7c239d9258845eb493f17d731df99] - -* Wed Nov 15 2023 Dumitru Ceara - 23.09.0-44 -- py-requirements: Remove hacking dependency and use recent flake8. -[Upstream: c6a631f066eea105c57c265dc68257d1b5ee18e4] - -* Fri Nov 03 2023 Xavier Simonart - 23.09.0-43 -- ovn-ic: wakeup on ovsdb transaction failures -[Upstream: be4364e62ac739744c1ef5bdd74a85fe39d6e37d] - -* Fri Nov 03 2023 Xavier Simonart - 23.09.0-42 -- ovn-ic: fix potential segmentation violation when ts is deleted -[Upstream: 5f84ff658bfd1c26bd9749c3d2e09a7e3567a8bd] - -* Fri Oct 20 2023 Ales Musil - 23.09.0-41 -- controller, northd: Wait for cleanup before replying to exit -[Upstream: aae5b2ec8ec9f4f9f7c9738d23818c2c4967627c] - -* Fri Oct 20 2023 Mark Michelson - 23.09.0-40 -- tests: Add missing check for scapy. -[Upstream: ea9310a5f1e37b373abffd85f7a8dd4fefc30c4e] - -* Wed Oct 18 2023 Ales Musil - 23.09.0-39 -- ci: Apply the ASAN workaround only for Clang <16 -[Upstream: 15bf24b889b178d4cdbb6166d3bc5434ec59f9fc] - -* Wed Oct 18 2023 Ales Musil - 23.09.0-38 -- ci: Use proper uname argument to get the HW type -[Upstream: 2efc23f3edf0293ec81a167e1c4bf99fe5601ca2] - -* Thu Oct 12 2023 Dumitru Ceara - 23.09.0-37 -- tests: Wait for new ovn-controllers to connect to Southbound. -[Upstream: 349266aac20f229b10ef0313c9f4e6b5f1af4ede] - -* Wed Oct 11 2023 Dumitru Ceara - 23.09.0-36 -- northd: Reset ls_datapath_group if not all chassis support it. -[Upstream: df7656fbf6a4ec1175b8f464a1aa6ed6e74fde29] - -* Wed Oct 11 2023 Lorenzo Bianconi - 23.09.0-35 -- northd: introduce ls_datapath_group column in lb sb db table -[Upstream: 276b9d47183ebd31c382742025e562fda8d14d11] - -* Wed Oct 11 2023 Lorenzo Bianconi - 23.09.0-34 -- northd: sync lb applied to logical routers in sb db lb table (#2193323) -[Upstream: c33398e32b2753dd6c0cecf35ba48ad8faa69bfc] - -* Tue Oct 10 2023 shylou - 23.09.0-33 -- northd: Avoid snat on reply packets for dgw -[Upstream: e8c79cecef9d6e15673be1a604baaaca083f0016] - -* Tue Oct 10 2023 Dumitru Ceara - 23.09.0-32 -- northd: Incrementally process SB.Load_balancer updates. -[Upstream: a9788ef39e003b04ec426761833d85bbec1f3b84] - -* Tue Oct 10 2023 Dumitru Ceara - 23.09.0-31 -- tests: Add missing --wait=sb to the LB I-P test. -[Upstream: cadfefdf1c6457d25b6d1f93e217493739418365] - -* Tue Oct 10 2023 Ales Musil - 23.09.0-30 -- system-tests: Make sure that IPv6 address is available right away -[Upstream: dc9eb3a1cc95accc37165902006db6eeab25fba6] - -* Tue Oct 10 2023 Ihar Hrachyshka - 23.09.0-29 -- Don't mention packet cloning when failing to find tunnel -[Upstream: 44ee1a6cb40395617f5dbab5829c9f436c16a783] - -* Tue Oct 10 2023 Ales Musil - 23.09.0-28 -- northd: Allow need frag to be SNATed -[Upstream: 94c8f952bb848806e04a857a84718d2744cfcb9f] - -* Tue Oct 10 2023 Ihar Hrachyshka - 23.09.0-27 -- docs: require ovn-set-local-ip for co-located ovn-controllers -[Upstream: 16bdac7965ae805040a107fc3cdade5bf4db63a2] - -* Tue Oct 10 2023 Ilya Maximets - 23.09.0-26 -- memory-trim: Fix timestamp overflow warning right after reboot. -[Upstream: 32ab7d94f9258ad6e938c715380a567b4a363a62] - -* Mon Oct 09 2023 Xavier Simonart - 23.09.0-25 -- Fix missing flows in ls_in_dhcp_options table -[Upstream: bb8fe6add97ab5fed5e4618b32c16e174faf44c8] - -* Mon Oct 09 2023 Xavier Simonart - 23.09.0-24 -- controller: throttle port claim attempts from if-status -[Upstream: bd32a6646d21c766497494c7a1a4add05a40cd22] - -* Fri Oct 06 2023 Ales Musil - 23.09.0-23 -- ci: Free up additional space for ovn-k jobs. -[Upstream: d30fe25c45620017ceea4f06e6e3ebd316ba734f] - -* Fri Oct 06 2023 Ales Musil - 23.09.0-22 -- ci: Handle google-cloud-sdk -> google-cloud-cli package name change. -[Upstream: 42e81bdcebc8cd744deb8034d2fb89ec3b85bf4a] - -* Fri Oct 06 2023 Dumitru Ceara - 23.09.0-21 -- ci: Free up disk space in a more robust way. -[Upstream: cf99264e252c20edf93ab5735e18aa3225c98398] - -* Fri Oct 06 2023 Dumitru Ceara - 23.09.0-20 -- ci: Update apt cache before installing gcc-multilib. -[Upstream: fd79876c2757f9074d38bd41cc36f59f3ba26138] - -* Fri Oct 06 2023 Xavier Simonart - 23.09.0-19 -- tests: fixed "send gratuitous ARP for NAT rules on HA distributed router" -[Upstream: 94b671cf89b27f54d1d03149de900994c79df415] - -* Fri Oct 06 2023 Xavier Simonart - 23.09.0-18 -- tests: move trim_zeros() to ovn-macros -[Upstream: 56b0435d8431518f4299c622a6ec9fc8770b8b0c] - -* Fri Oct 06 2023 Xavier Simonart - 23.09.0-17 -- tests: skip test "MAC binding aging" if scapy not available. -[Upstream: 148431080738bdec5e625a9ce8d470e365ee14f2] - -* Fri Oct 06 2023 Xavier Simonart - 23.09.0-16 -- tests: fixed "L2 Drop and Allow ACL w/ Stateful ACL" -[Upstream: 6f8719c60b8a578d564d3a6147f963fddeeacaa1] - -* Fri Oct 06 2023 Xavier Simonart - 23.09.0-15 -- tests: fixed multiple tests missing ovn-nbctl "wait" -[Upstream: f8cdfedacf212d9f103c2adba0c6805c01c68ff4] - -* Fri Oct 06 2023 Xavier Simonart - 23.09.0-14 -- tests: fixed "options:requested-chassis for logical port" -[Upstream: cd74dda22b255890a120988e8737c22a25c49957] - -* Fri Oct 06 2023 Xavier Simonart - 23.09.0-13 -- tests: fixed "Logical router policy packet marking" -[Upstream: e5a794dc30b087e0c78764326c86a3258f97bcc0] - -* Fri Oct 06 2023 Xavier Simonart - 23.09.0-12 -- tests: fixed multiple ovn-ic tests -[Upstream: 0575b97dc676d8c225bc8f63befec1bf1390ebe1] - -* Thu Oct 05 2023 Ales Musil - 23.09.0-11 -- pinctrl: Reply with correct destination for ICMPv6 RA packets -[Upstream: b93f36a248f7df3eb71b5141c5deadec7c18ee24] - -* Mon Oct 02 2023 Han Zhou - 23.09.0-10 -- ovn-controller: Add monitor condition for FDB. -[Upstream: c4008ae520af2561cfd68749227a8a468277e2e5] - -* Thu Sep 21 2023 Ihar Hrachyshka - 23.09.0-9 -- Rename scapy-server into scapy-server.py -[Upstream: d16ec6f9a063a0cb2d7bac56e23dd60d0c856b76] - -* Wed Sep 20 2023 Patryk Diak - 23.09.0-8 -- Add ovnkube-identity binary to the ovn-kubernetes Dockerfile -[Upstream: 35d9e42bc3e60629701743ca7e9d6890511cf0f5] - -* Tue Sep 19 2023 Ihar Hrachyshka - 23.09.0-7 -- tests: offload scapy transformations to a separate unixctl daemon -[Upstream: 4a82a49363a591d429d86d60f9120166ea04cb91] - -* Tue Sep 19 2023 Ales Musil - 23.09.0-6 -- northd: Remove hosting-chassis only if it's specified -[Upstream: 0b45a1a1cc6f081184d599ba139847ff03d90912] - -* Fri Sep 15 2023 Xavier Simonart - 23.09.0-5 -- QoS: Properly set qos when ovs db is read only (#2234349) -[Upstream: 9c56ac4b74f6b964f102b94404b350417b1cd772] - -* Fri Sep 15 2023 Mark Michelson - 23.09.0-4 -- Prepare for 23.09.1. -[Upstream: 36f37341d32589dcd8d4bfeb023046b07dea1a44] +* Tue Mar 12 2024 Mark Michelson - 23.09.3-4 +- Prepare for 23.09.4. +[Upstream: 5ce1740aaa02ebeed561ffb6298b71035b5c908a]