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..dd2aa1bfd 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-2304-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
+
+ upload_image_script:
+ - curl -s -X POST -T /tmp/image.tar http://$CIRRUS_HTTP_CACHE_HOST/${CIRRUS_CHANGE_IN_REPO}
- arm_container:
- image: ghcr.io/ovn-org/ovn-tests:fedora
- memory: 4G
- cpu: 2
+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,16 @@ arm_unit_tests_task:
name: ARM64 ${CC} ${TESTSUITE} ${TEST_RANGE}
+ install_dependencies_script:
+ - sudo apt update
+ - sudo apt install -y podman
+
+ 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..bdd118087 100644
--- a/.github/workflows/containers.yml
+++ b/.github/workflows/containers.yml
@@ -15,7 +15,7 @@ env:
jobs:
container:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
strategy:
matrix:
distro: [ fedora, ubuntu ]
diff --git a/.github/workflows/ovn-fake-multinode-tests.yml b/.github/workflows/ovn-fake-multinode-tests.yml
index 75c5ca818..25610df53 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:
@@ -69,7 +69,7 @@ jobs:
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:
@@ -99,13 +99,18 @@ jobs:
XDG_RUNTIME_DIR: ''
steps:
+ - name: Check out ovn
+ uses: actions/checkout@v3
+
- 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
with:
@@ -153,7 +158,7 @@ jobs:
- name: set up python
uses: actions/setup-python@v4
with:
- python-version: '3.x'
+ python-version: '3.12'
- name: Check out ovn
uses: actions/checkout@v3
diff --git a/.github/workflows/ovn-kubernetes.yml b/.github/workflows/ovn-kubernetes.yml
index 69ab0566d..1689396d6 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: |
@@ -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,18 +95,14 @@ jobs:
KIND_IPV6_SUPPORT: "${{ matrix.ipfamily == 'IPv6' || matrix.ipfamily == 'dualstack' }}"
steps:
- - 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
+ - name: Free up disk space
+ run: |
+ . .ci/linux-util.sh
+ free_up_disk_space_ubuntu
+
- name: Check out ovn-kubernetes
uses: actions/checkout@v3
with:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index fe2a14c40..aa01dc7e9 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -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@v3
+
+ - 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@v3
+ 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
@@ -157,13 +209,25 @@ jobs:
sort -V | tail -1)
working-directory: ovs
- - name: cache
+ - name: cache dpdk
if: matrix.cfg.dpdk != ''
uses: actions/cache@v3
with:
path: dpdk-dir
key: ${{ needs.build-dpdk.outputs.dpdk_key }}
+ - name: image cache
+ uses: actions/cache@v3
+ with:
+ path: /tmp/image.tar
+ key: ${{ github.sha }}
+
+ - 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
@@ -225,7 +289,7 @@ jobs:
- name: set up python
uses: actions/setup-python@v4
with:
- python-version: '3.x'
+ python-version: '3.12'
- name: prepare
run: ./.ci/osx-prepare.sh
- name: build
@@ -239,8 +303,8 @@ jobs:
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:
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/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 <name> from line <N> (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
diff --git a/NEWS b/NEWS
index 75e046ab3..ed74d0f38 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,11 @@
+OVN v23.09.2 - xx xxx xxxx
+--------------------------
+
+
+OVN v23.09.1 - 01 Dec 2023
+--------------------------
+ - Bug fixes
+
OVN v23.09.0 - 15 Sep 2023
----------------------------
- Added FDB aging mechanism, that is disabled by default.
diff --git a/configure.ac b/configure.ac
index ab404b959..e4d5134dd 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.2, 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/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..a6f13ccc4 100644
--- a/controller/chassis.c
+++ b/controller/chassis.c
@@ -369,6 +369,7 @@ 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");
}
/*
@@ -502,6 +503,12 @@ 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;
+ }
+
return false;
}
@@ -632,6 +639,7 @@ 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);
}
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/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 <code>ovn-controller</code> when create
tunnel ports should set <code>local_ip</code> 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 <code>ovn-controller</code> instances on the same
+ chassis, in which case this setting will guarantee that their tunnel
+ ports have unique configuration and can exist in parallel.
</dd>
<dt><code>external_ids:garp-max-timeout-sec</code></dt>
<dd>
@@ -398,9 +401,11 @@
names on the same host using the same <code>vswitchd</code> 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
+ <code>external_ids:ovn-set-local-ip</code> 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.
</p>
<p>
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index b3e4e0da8..6787dda80 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");
+
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();
@@ -5508,10 +5561,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 +5696,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_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 +5871,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) {
@@ -5864,6 +5933,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 +6012,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 +6063,7 @@ loop_done:
memory_wait();
poll_block();
if (should_service_stop()) {
- exiting = true;
+ exit_args.exiting = true;
}
}
@@ -6000,7 +6071,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 +6123,6 @@ loop_done:
}
free(ovn_version);
- unixctl_server_destroy(unixctl);
lflow_destroy();
ofctrl_destroy();
pinctrl_destroy();
@@ -6077,6 +6147,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();
@@ -6156,6 +6228,7 @@ parse_options(int argc, char *argv[])
break;
case 'n':
+ free(cli_system_id);
cli_system_id = xstrdup(optarg);
break;
@@ -6200,16 +6273,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..3b862ca34 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;
diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index ff5a3444c..ececbdb48 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);
@@ -3577,7 +3595,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 +6245,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 +6363,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 +6398,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 +7788,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 +7802,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 +7848,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 +7864,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 +8219,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 +8229,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 +8261,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 +8272,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..479d4c944 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
+OVN (23.09.2-1) unstable; urgency=low
+ [ OVN team ]
+ * New upstream version
+
+ -- OVN team <dev@openvswitch.org> Fri, 01 Dec 2023 14:41:31 -0500
+
+OVN (23.09.1-1) unstable; urgency=low
+ [ OVN team ]
+ * New upstream version
+
+ -- OVN team <dev@openvswitch.org> Fri, 01 Dec 2023 14:41:31 -0500
+
ovn (23.09.0-1) unstable; urgency=low
* New upstream version
diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
index e2023c2ba..020b1d60b 100644
--- a/ic/ovn-ic.c
+++ b/ic/ovn-ic.c
@@ -1630,13 +1630,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) {
@@ -2216,10 +2221,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/features.h b/include/ovn/features.h
index 3bf536127..2c47ab766 100644
--- a/include/ovn/features.h
+++ b/include/ovn/features.h
@@ -26,6 +26,7 @@
#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"
/* OVS datapath supported features. Based on availability OVN might generate
* different types of openflows.
@@ -48,5 +49,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..272277ec4 100644
--- a/include/ovn/logical-fields.h
+++ b/include/ovn/logical-fields.h
@@ -77,6 +77,7 @@ 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,
};
/* MFF_LOG_FLAGS_REG flag assignments */
@@ -124,6 +125,10 @@ 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),
+
};
/* OVN logical fields
diff --git a/lib/actions.c b/lib/actions.c
index b880927b6..4d408d82d 100644
--- a/lib/actions.c
+++ b/lib/actions.c
@@ -5004,6 +5004,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 <config.h>
#include <string.h>
-#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..b31b5f6dd 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. */
@@ -145,11 +158,19 @@ ovs_feature_get_openflow_cap(const char *br_name)
/* 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 +184,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 +199,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 +262,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..7a1e66d0a 100644
--- a/lib/logical-fields.c
+++ b/lib/logical-fields.c
@@ -129,6 +129,10 @@ 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);
/* 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-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..8aeca33f8 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -491,6 +491,15 @@ 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;
+ }
}
}
@@ -4511,6 +4520,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 +4543,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 +4567,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 +4576,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 +4588,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 +4615,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 +4628,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 +4641,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 +4671,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 +4695,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(&ls_dp_groups);
+
+ HMAP_FOR_EACH_POP (dpg, node, &lr_dp_groups) {
bitmap_free(dpg->bitmap);
free(dpg);
}
- hmap_destroy(&dp_groups);
+ hmap_destroy(&lr_dp_groups);
struct sb_lb *sb_lb;
HMAP_FOR_EACH_POP (sb_lb, hmap_node, &sb_lbs) {
@@ -4659,6 +4724,33 @@ sync_lbs(struct ovsdb_idl_txn *ovnsb_txn,
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
@@ -5089,23 +5181,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 +5380,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 +5397,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 +5670,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 +7044,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,
@@ -9307,6 +9400,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,
@@ -13047,9 +13171,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));
@@ -13895,7 +14019,15 @@ build_icmperr_pkt_big_flows(struct ovn_port *op, int mtu, struct hmap *lflows,
outport->json_key)
: NULL;
- if (op->lrp_networks.ipv4_addrs) {
+ char *ip4_src = NULL;
+
+ if (outport && outport->lrp_networks.ipv4_addrs) {
+ ip4_src = outport->lrp_networks.ipv4_addrs[0].addr_s;
+ } else if (op->lrp_networks.ipv4_addrs) {
+ ip4_src = op->lrp_networks.ipv4_addrs[0].addr_s;
+ }
+
+ if (ip4_src) {
ds_clear(match);
ds_put_format(match, "inport == %s && %sip4 && "REGBIT_PKT_LARGER
" && "REGBIT_EGRESS_LOOPBACK" == 0", op->json_key,
@@ -13915,9 +14047,8 @@ build_icmperr_pkt_big_flows(struct ovn_port *op, int mtu, struct hmap *lflows,
"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));
+ op->lrp_networks.ea_s, ip4_src, 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,
@@ -13928,7 +14059,15 @@ build_icmperr_pkt_big_flows(struct ovn_port *op, int mtu, struct hmap *lflows,
&op->nbrp->header_);
}
- if (op->lrp_networks.ipv6_addrs) {
+ char *ip6_src = NULL;
+
+ if (outport && outport->lrp_networks.ipv6_addrs) {
+ ip6_src = outport->lrp_networks.ipv6_addrs[0].addr_s;
+ } else if (op->lrp_networks.ipv6_addrs) {
+ ip6_src = op->lrp_networks.ipv6_addrs[0].addr_s;
+ }
+
+ if (ip6_src) {
ds_clear(match);
ds_put_format(match, "inport == %s && %sip6 && "REGBIT_PKT_LARGER
" && "REGBIT_EGRESS_LOOPBACK" == 0", op->json_key,
@@ -13948,9 +14087,8 @@ build_icmperr_pkt_big_flows(struct ovn_port *op, int mtu, struct hmap *lflows,
"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));
+ op->lrp_networks.ea_s, ip6_src, 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,
@@ -15217,6 +15355,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 +15414,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]) {
@@ -17655,6 +17792,7 @@ northd_init(struct northd_data *data)
.mac_binding_timestamp = true,
.ct_lb_related = true,
.fdb_timestamp = true,
+ .ls_dpg_column = true,
};
data->ovn_internal_version_changed = false;
sset_init(&data->svc_monitor_lsps);
@@ -18051,13 +18189,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..76dfc392d 100644
--- a/northd/northd.h
+++ b/northd/northd.h
@@ -70,6 +70,7 @@ struct chassis_features {
bool mac_binding_timestamp;
bool ct_lb_related;
bool fdb_timestamp;
+ bool ls_dpg_column;
};
/* A collection of datapaths. E.g. all logical switch datapaths, or all
@@ -365,7 +366,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..97718821f 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -399,14 +399,16 @@
<p>
This table looks up the MAC learning table of the logical switch
datapath to check if the <code>port-mac</code> 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.
</p>
<ul>
<li>
<p>
- For each such logical port <var>p</var> whose port security
+ For each such VIF logical port <var>p</var> whose port security
is disabled and 'unknown' address set following flow
is added.
</p>
@@ -420,6 +422,22 @@
</ul>
</li>
+ <li>
+ <p>
+ For each such localnet logical port <var>p</var> following flow
+ is added.
+ </p>
+
+ <ul>
+ <li>
+ Priority 100 flow with the match
+ <code>inport == <var>p</var></code> and action
+ <code>flags.localnet = 1;</code>
+ <code>reg0[11] = lookup_fdb(inport, eth.src); next;</code>
+ </li>
+ </ul>
+ </li>
+
<li>
One priority-0 fallback flow that matches all packets and advances to
the next table.
@@ -429,17 +447,20 @@
<h3>Ingress Table 3: Learn MAC of 'unknown' ports.</h3>
<p>
- 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 <code>lookup_fdb</code> 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.
</p>
<ul>
<li>
<p>
- For each such logical port <var>p</var> whose port security
- is disabled and 'unknown' address set following flow
+ For each such VIF logical port <var>p</var> whose port security is
+ disabled and 'unknown' address set and localnet port following flow
is added.
</p>
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 68fc8836e..b2c5552f6 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;
@@ -752,7 +751,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 +773,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 +868,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 +880,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 +1024,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 +1057,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 +1074,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 @@
<column name="options" key="ethtype">
Optional. VLAN EtherType field value for encapsulating VLAN
- headers. Supported values: 802.11q (default), 802.11ad.
+ headers. Supported values: 802.1q (default), 802.1ad.
</column>
<column name="options" key="localnet_learn_fdb"
diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema
index 7b20aa21b..a512e00e5 100644
--- a/ovn-sb.ovsschema
+++ b/ovn-sb.ovsschema
@@ -1,7 +1,7 @@
{
"name": "OVN_Southbound",
- "version": "20.27.4",
- "cksum": "3194181501 30531",
+ "version": "20.29.0",
+ "cksum": "3967183656 30959",
"tables": {
"SB_Global": {
"columns": {
@@ -534,6 +534,14 @@
{"type": {"key": {"type": "uuid",
"refTable": "Logical_DP_Group"},
"min": 0, "max": 1}},
+ "ls_datapath_group":
+ {"type": {"key": {"type": "uuid",
+ "refTable": "Logical_DP_Group"},
+ "min": 0, "max": 1}},
+ "lr_datapath_group":
+ {"type": {"key": {"type": "uuid",
+ "refTable": "Logical_DP_Group"},
+ "min": 0, "max": 1}},
"options": {
"type": {"key": "string",
"value": "string",
diff --git a/ovn-sb.xml b/ovn-sb.xml
index 46aedf973..519b9da8f 100644
--- a/ovn-sb.xml
+++ b/ovn-sb.xml
@@ -1721,9 +1721,12 @@
<p>
Looks up <var>A</var> in fdb table. If an entry is found
- and the the logical port key is <var>P</var>, <code>P</code>,
+ and the logical port key is <var>P</var>, <code>P</code>,
stores <code>1</code> in the 1-bit subfield
- <var>R</var>, else 0.
+ <var>R</var>, else 0. If <code>flags.localnet</code> is set
+ then <code>1</code> is stored if an entry is found and the
+ logical port key is <var>P</var> or if an entry is found and
+ the entry port type is VIF.
</p>
<p>
@@ -4888,10 +4891,22 @@ tcp.flags = RST;
</column>
<column name="datapath_group">
+ 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.
+ </column>
+
+ <column name="ls_datapath_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.
</column>
+ <column name="lr_datapath_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.
+ </column>
+
<group title="Load_Balancer options">
<column name="options" key="hairpin_snat_ip">
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, '<area>: <summary>', 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/ovn-controller-vtep.at b/tests/ovn-controller-vtep.at
index 73971b3f4..50f31b22f 100644
--- a/tests/ovn-controller-vtep.at
+++ b/tests/ovn-controller-vtep.at
@@ -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..6f496d142 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.
@@ -526,6 +525,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 +578,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 +2094,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 +2118,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
@@ -2202,6 +2202,10 @@ OVS_APP_EXIT_AND_WAIT([ovn-controller])
# 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])
+# 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"
@@ -2214,10 +2218,18 @@ sleep 2
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])
+# 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])
+
+# 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
@@ -2230,7 +2242,7 @@ 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])
-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 +2250,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
diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at
index d265bb90b..d4c436f84 100644
--- a/tests/ovn-ic.at
+++ b/tests/ovn-ic.at
@@ -92,6 +92,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 +157,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 +229,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 +293,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 +338,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 +533,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 +557,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 +592,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 +918,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 +944,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 +968,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 +976,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 +1046,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 +1072,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 +1096,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 +1105,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 +1125,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 +1145,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 +1171,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 +1210,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 +1228,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 +1250,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
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..bb93fa5f0 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])])
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..c32122025 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;)
])
@@ -2860,7 +2868,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 +2879,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 +2905,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 +2959,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 +2982,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 +2993,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 +4619,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 +5118,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 +5133,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 +5154,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 +5171,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 +5191,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 +5211,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 +5237,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 +5399,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 +5447,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 +5529,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 +5595,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
@@ -6019,9 +6054,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
@@ -6105,10 +6140,10 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=.
table=??(lr_in_chk_pkt_len ), priority=0 , match=(1), action=(next;)
table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;)
table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;)
- table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw0" && 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: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=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=150 , match=(inport == "lr0-sw0" && 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:01; 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 = 1500; next(pipeline=ingress, table=0); };)
+ 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:20ff:fe20:1213; 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 = 172.168.0.100; 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: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_in_admission.*check_pkt_larger" lr0flows | sort], [0], [dnl
@@ -6136,10 +6171,10 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=.
table=??(lr_in_chk_pkt_len ), priority=0 , match=(1), action=(next;)
table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;)
table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;)
- table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw0" && 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: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=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=150 , match=(inport == "lr0-sw0" && 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:01; 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 = 1500; next(pipeline=ingress, table=0); };)
+ 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:20ff:fe20:1213; 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 = 172.168.0.100; 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: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_in_admission.*check_pkt_larger" lr0flows | sort], [0], [dnl
@@ -6165,10 +6200,10 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=.
table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-public"), action=(reg9[[1]] = check_pkt_larger(1514); next;)
table=??(lr_in_chk_pkt_len ), priority=55 , match=(outport == "lr0-public" && (tcp)), action=(next;)
table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;)
- table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-sw0" && 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: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=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=150 , match=(inport == "lr0-sw0" && 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:01; 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 = 1500; next(pipeline=ingress, table=0); };)
+ 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:20ff:fe20:1213; 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 = 172.168.0.100; 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: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 "lr_in_admission" lr0flows | grep -e "check_pkt_larger" -e "tcp" | sort], [0], [dnl
@@ -6190,14 +6225,14 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=.
table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); next;)
table=??(lr_in_chk_pkt_len ), priority=55 , match=(outport == "lr0-public" && (tcp)), action=(next;)
table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;)
- table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {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=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-sw0" && 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: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=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=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=150 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; 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 = 1400; next(pipeline=ingress, table=0); };)
+ 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:ff:fe00:ff01; 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-sw0" && 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:01; 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 = 1500; next(pipeline=ingress, table=0); };)
+ 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:20ff:fe20:1213; 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 = 172.168.0.100; 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:20ff:fe20:1213; 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 = 10.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: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 "lr_in_admission.*check_pkt_larger" lr0flows | sort], [0], [dnl
@@ -6229,14 +6264,14 @@ AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=.
table=??(lr_in_chk_pkt_len ), priority=55 , match=(outport == "lr0-public" && (tcp)), action=(next;)
table=??(lr_in_chk_pkt_len ), priority=55 , match=(outport == "lr0-sw0" && (tcp)), action=(next;)
table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;)
- table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {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=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-sw0" && 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: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=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=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=150 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; 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 = 1400; next(pipeline=ingress, table=0); };)
+ 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:ff:fe00:ff01; 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-sw0" && 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:01; 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 = 1500; next(pipeline=ingress, table=0); };)
+ 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:20ff:fe20:1213; 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 = 172.168.0.100; 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:20ff:fe20:1213; 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 = 10.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: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 "lr_in_admission" lr0flows | grep -e "check_pkt_larger" -e "tcp" | sort], [0], [dnl
@@ -6255,15 +6290,16 @@ check ovn-nbctl --wait=sb clear logical_router_port lr0-public options
ovn-sbctl dump-flows lr0 > lr0flows
AT_CAPTURE_FILE([lr0flows])
+grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=../table=??/' | sort
AT_CHECK([grep -e "chk_pkt_len" -e "lr_in_larger_pkts" lr0flows | sed 's/table=../table=??/' | sort], [0], [dnl
table=??(lr_in_chk_pkt_len ), priority=0 , match=(1), action=(next;)
table=??(lr_in_chk_pkt_len ), priority=50 , match=(outport == "lr0-sw0"), action=(reg9[[1]] = check_pkt_larger(1414); next;)
table=??(lr_in_chk_pkt_len ), priority=55 , match=(outport == "lr0-sw0" && (tcp)), action=(next;)
table=??(lr_in_larger_pkts ), priority=0 , match=(1), action=(next;)
- table=??(lr_in_larger_pkts ), priority=150 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {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=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=150 , match=(inport == "lr0-public" && outport == "lr0-sw0" && ip4 && reg9[[1]] && reg9[[0]] == 0), action=(icmp4_error {reg9[[0]] = 1; reg9[[1]] = 0; eth.dst = 00:00:20:20:12:13; 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 = 1400; next(pipeline=ingress, table=0); };)
+ 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:ff:fe00:ff01; 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 = 10.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:ff01; 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
@@ -7361,9 +7397,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 +7473,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
@@ -8618,7 +8654,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 +8737,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)
@@ -8985,7 +9021,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 +10043,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 +10074,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 +10110,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 +10127,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 +10138,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 +10167,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 +10258,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 +10381,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 +10433,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 +10476,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 +10485,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 +10493,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 +10507,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 +10515,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 +10527,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 +10536,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 +10545,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 +10554,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 +10563,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 +10573,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 +10584,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 +10593,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 +10602,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 +10611,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 +10620,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 +10629,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 +10637,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 +10655,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 +10691,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 +10699,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 +10708,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 +10717,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 +10726,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 +10750,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 +10759,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 +10768,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 +10777,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 +10820,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 +10854,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 +10862,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 +10871,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 +10879,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 +10887,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 +10897,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 +10907,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 +10915,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..13f5575be 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=:
+ 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],
@@ -2198,13 +2219,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 +3870,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 +4671,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 +4876,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 +5354,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 +5434,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])
@@ -6758,13 +6811,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 +7009,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 +7168,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 +7188,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 +7206,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 +7342,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 +7443,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 +7547,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 +7684,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 +8460,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 +8776,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 +9062,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 +9117,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 +9313,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 +9333,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 +10751,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 +11030,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 +11049,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 +11069,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 +11148,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 +11168,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 +11232,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 +11252,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 +11279,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 +11299,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
@@ -11481,30 +11481,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 +12183,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 +12214,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 +12542,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 +12609,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
+prefix="fdad:1234:5678::"
+
# 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
+ra=$(prepare_ra_opt "" 0)
+src_mac="fa:16:3e:00:00:02"
+src_lla="fe80::f816:3eff:fe00:2"
-# NXT_RESUME should be 1.
-OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
+test_ipv6_ra 1 $src_mac $src_lla "$ra" 0 $prefix "" "" ""
+check_packets 1
-$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets
+# Check with RA with src being "::".
+ovn-nbctl --wait=hv lsp-set-port-security lp1 ""
-cat 1.expected | cut -c -112 > expout
-AT_CHECK([cat 1.packets | cut -c -112], [0], [expout])
+test_ipv6_ra 1 $src_mac "::" "$ra" 0 $prefix "" "" ""
+check_packets 1
-# 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
+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 +12736,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])
-
-# Skipping the ICMPv6 checksum.
-cat 2.expected | cut -c 117- > expout
-AT_CHECK([cat 2.packets | cut -c 117-], [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"
-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 +12754,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`])
-
-$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])
+ra=$(prepare_ra_opt "stateful" 1)
+src_mac="fa:16:3e:00:00:04"
+src_lla="fe80::f816:3eff:fe00:4"
-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 +12768,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
-
-# 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
+ra=$(prepare_ra_opt "stateless" 0)
+src_mac="fa:16:3e:00:00:02"
+src_lla="fe80::f816:3eff:fe00:2"
-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], [])
@@ -13879,33 +13833,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 +13850,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 +13857,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 +13900,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
+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_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 +14245,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 +14796,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 +14886,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
@@ -16188,7 +16103,7 @@ 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
@@ -16276,7 +16191,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,6 +18904,46 @@ for sf in 0 1; do
done
done
+check_packets() {
+ n_allowed=$1
+ > expected
+ > received
+ for i in 1 2 3; do
+ echo "--- hv$i vif${i}1" | tee -a expected >> received
+ sort ${i}1.expected >> expected
+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv$i/vif${i}1-tx.pcap | sort >> received
+ echo | tee -a expected >> received
+ done
+
+ # need to verify the log for ACL hit as well, since in the allow case
+ # (unlike the drop case) it is tricky to pass just with the expected;
+ # since with the stateful rule the packet will still get by (default
+ # rule) even if it doesn't hit the allow rule.
+ # The hit count for the ACL is 6 (1 unicast + 2 non-unicast) * 2
+ # (with/without stateful rule) for hv1 and hv2, each.
+ cat >>expected <<EOF
+--- acl logging
+hv1_drop hit 6
+hv2_drop hit 6
+hv1_allow hit $n_allowed
+hv2_allow hit $n_allowed
+EOF
+
+cat >>received <<EOF
+--- acl logging
+hv1_drop hit `grep -c 'acl_log.*|INFO|name="drop-acl"' hv1/ovn-controller.log`
+hv2_drop hit `grep -c 'acl_log.*|INFO|name="drop-acl"' hv2/ovn-controller.log`
+hv1_allow hit `grep -c 'acl_log.*|INFO|name="allow-acl"' hv1/ovn-controller.log`
+hv2_allow hit `grep -c 'acl_log.*|INFO|name="allow-acl"' hv2/ovn-controller.log`
+EOF
+
+ $at_diff expected received >/dev/null
+}
+
+# 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
@@ -19037,41 +18992,7 @@ 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() {
- > expected
- > received
- for i in 1 2 3; do
- echo "--- hv$i vif${i}1" | tee -a expected >> received
- sort ${i}1.expected >> expected
- $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv$i/vif${i}1-tx.pcap | sort >> received
- echo | tee -a expected >> received
- done
-
- # need to verify the log for ACL hit as well, since in the allow case
- # (unlike the drop case) it is tricky to pass just with the expected;
- # since with the stateful rule the packet will still get by (default
- # rule) even if it doesn't hit the allow rule.
- # The hit count for the ACL is 6 (1 unicast + 2 non-unicast) * 2
- # (with/without stateful rule) for hv1 and hv2, each.
- cat >>expected <<EOF
---- acl logging
-hv1_drop hit 6
-hv2_drop hit 6
-hv1_allow hit 6
-hv2_allow hit 6
-EOF
-
-cat >>received <<EOF
---- acl logging
-hv1_drop hit `grep -c 'acl_log.*|INFO|name="drop-acl"' hv1/ovn-controller.log`
-hv2_drop hit `grep -c 'acl_log.*|INFO|name="drop-acl"' hv2/ovn-controller.log`
-hv1_allow hit `grep -c 'acl_log.*|INFO|name="allow-acl"' hv1/ovn-controller.log`
-hv2_allow hit `grep -c 'acl_log.*|INFO|name="allow-acl"' hv2/ovn-controller.log`
-EOF
-
- $at_diff expected received >/dev/null
-}
-OVS_WAIT_UNTIL([check_packets], [$at_diff -F'^---' expected received])
+OVS_WAIT_UNTIL([check_packets 6], [$at_diff -F'^---' expected received])
OVN_CLEANUP([hv1],[hv2],[hv3])
@@ -19790,11 +19711,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 +19792,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 +19816,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 +19878,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 +19901,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 +19979,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 +20003,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 +20053,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 +20080,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
@@ -20568,12 +20456,12 @@ test_ip_packet_larger() {
expected=${expected}0000000000000000000000000000
echo $expected > br_phys_n1.expected
else
- src_ip=`ip_to_hex 10 0 0 1`
+ src_ip=`ip_to_hex 172.168.0.100`
dst_ip=`ip_to_hex 10 0 0 3`
# pkt len should be 146 (28 (icmp packet) + 118 (orig ip + payload))
reply_pkt_len=008e
ip_csum=fc97
- icmp_reply=${src_mac}${dst_mac}08004500${reply_pkt_len}00004000fe01686b
+ icmp_reply=${src_mac}${dst_mac}08004500${reply_pkt_len}00004000fe01c55f
icmp_reply=${icmp_reply}${src_ip}${dst_ip}0304${ip_csum}0000$(printf "%04x" $mtu)
icmp_reply=${icmp_reply}4500${pkt_len}000000003f01c4dd
icmp_reply=${icmp_reply}${orig_packet_l3}
@@ -20665,7 +20553,7 @@ test_ip6_packet_larger() {
local ipv6_src=10000000000000000000000000000003
local ipv6_dst=20000000000000000000000000000002
- local ipv6_rt=10000000000000000000000000000001
+ local ipv6_rt=20000000000000000000000000000001
local payload=0000000000000000000000000000000000000000
local payload=${payload}0000000000000000000000000000000000000000
@@ -21223,6 +21111,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 +23315,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 +23354,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 +26302,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 +26517,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 +27879,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 +27907,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 +28034,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
@@ -30785,7 +30683,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 +30733,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 +30853,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 +30994,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 +31009,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 +31163,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 +31343,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 +33613,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 +33626,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 +34355,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 +34372,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 +34456,7 @@ AT_CLEANUP
OVN_FOR_EACH_NORTHD([
AT_SETUP([MAC binding aging])
+AT_SKIP_IF([test $HAVE_SCAPY = no])
ovn_start
net_add n1
@@ -35389,37 +35274,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 +35649,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 +36582,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 +36714,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 +36858,548 @@ 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
+])
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..65c4884ea 100644
--- a/tests/system-common-macros.at
+++ b/tests/system-common-macros.at
@@ -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..039d71170 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=<cleared>/' |
-sed -e 's/vtag_orig=[[0-9]]*/vtag_orig=<cleared>/' |
-sed -e 's/vtag_reply=[[0-9]]*/vtag_reply=<cleared>/' | uniq], [0], [dnl
-sctp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=2,protoinfo=(state=<cleared>,vtag_orig=<cleared>,vtag_reply=<cleared>)
-sctp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=2,protoinfo=(state=<cleared>,vtag_orig=<cleared>,vtag_reply=<cleared>)
-])
-
-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=<cleared>/' |
-sed -e 's/vtag_orig=[[0-9]]*/vtag_orig=<cleared>/' |
-sed -e 's/vtag_reply=[[0-9]]*/vtag_reply=<cleared>/' | uniq], [0], [dnl
-sctp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=2,protoinfo=(state=<cleared>,vtag_orig=<cleared>,vtag_reply=<cleared>)
-sctp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=2,protoinfo=(state=<cleared>,vtag_orig=<cleared>,vtag_reply=<cleared>)
-])
-
-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=<cleared>/' |
-sed -e 's/vtag_orig=[[0-9]]*/vtag_orig=<cleared>/' |
-sed -e 's/vtag_reply=[[0-9]]*/vtag_reply=<cleared>/' | uniq], [0], [dnl
-sctp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=10,protoinfo=(state=<cleared>,vtag_orig=<cleared>,vtag_reply=<cleared>)
-sctp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=10,protoinfo=(state=<cleared>,vtag_orig=<cleared>,vtag_reply=<cleared>)
-])
-
-AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0.2) |
-sed -e 's/zone=[[0-9]]*/zone=<cleared>/' |
-sed -e 's/vtag_orig=[[0-9]]*/vtag_orig=<cleared>/' |
-sed -e 's/vtag_reply=[[0-9]]*/vtag_reply=<cleared>/' | uniq], [0], [dnl
-sctp,orig=(src=172.16.1.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>,vtag_orig=<cleared>,vtag_reply=<cleared>)
-sctp,orig=(src=172.16.1.2,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>,vtag_orig=<cleared>,vtag_reply=<cleared>)
-])
-
-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,7 +146,7 @@ tcp,orig=(src=172.16.1.2,dst=172.16.1.100,sport=<cleared>,dport=<cleared>),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:0xc0a80<cleared>02/'], [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:0xc0a80<cleared>02/'], [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:0xc0a80<cleared>02->NXM_NX_REG4[[]],load:0x50->NXM_NX_REG8[[0..15]]
])
@@ -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,7 +443,7 @@ tcp,orig=(src=fd72::2,dst=fd30::1,sport=<cleared>,dport=<cleared>),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:0xfd1<cleared>000000000000/'], [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:0xfd1<cleared>000000000000/'], [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:0xfd1<cleared>000000000000->NXM_NX_XXREG1[[64..127]],load:0x50->NXM_NX_REG8[[0..15]]
])
@@ -1115,3 +892,155 @@ 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/24
+
+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"])
+
+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..3ecf1db42 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
@@ -6306,8 +6272,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 +6287,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])
@@ -6513,8 +6477,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 +6592,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 +7332,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 +7355,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 +7386,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 +7405,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 +7425,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 +7455,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 +8680,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 +9212,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 +9337,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 +9364,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 +10805,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 +11662,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 +11705,417 @@ 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=<cleared>/' |
+sed 's/,protoinfo=.*$//' | uniq], [0], [dnl
+sctp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=2
+sctp,orig=(src=172.16.1.2,dst=30.0.0.1,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,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=<cleared>/' |
+sed 's/,protoinfo=.*$//' | uniq], [0], [dnl
+sctp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=2
+sctp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,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=<cleared>/' |
+sed 's/,protoinfo=.*$//' | uniq], [0], [dnl
+sctp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=10
+sctp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=10
+])
+
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0.2) |
+sed -e 's/zone=[[0-9]]*/zone=<cleared>/' |
+sed 's/,protoinfo=.*$//' | uniq], [0], [dnl
+sctp,orig=(src=172.16.1.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>
+sctp,orig=(src=172.16.1.2,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>
+])
+
+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 - 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, '<area>: <summary>', 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 @@
<p><code>--db-nb-cluster-remote-addr=<var>IP ADDRESS</var></code></p>
<p><code>--db-nb-cluster-remote-port=<var>PORT NUMBER</var></code></p>
<p><code>--db-nb-cluster-remote-proto=<var>PROTO (tcp/ssl)</var></code></p>
+ <p><code>--db-nb-election-timer=<var>Timeout in milliseconds</var></code></p>
<p><code>--db-sb-cluster-local-addr=<var>IP ADDRESS</var></code></p>
<p><code>--db-sb-cluster-local-port=<var>PORT NUMBER</var></code></p>
<p><code>--db-sb-cluster-local-proto=<var>PROTO (tcp/ssl)</var></code></p>
<p><code>--db-sb-cluster-remote-addr=<var>IP ADDRESS</var></code></p>
<p><code>--db-sb-cluster-remote-port=<var>PORT NUMBER</var></code></p>
<p><code>--db-sb-cluster-remote-proto=<var>PROTO (tcp/ssl)</var></code></p>
+ <p><code>--db-sb-election-timer=<var>Timeout in milliseconds</var></code></p>
<p><code>--db-ic-nb-cluster-local-addr=<var>IP ADDRESS</var></code></p>
<p><code>--db-ic-nb-cluster-local-port=<var>PORT NUMBER</var></code></p>
<p><code>--db-ic-nb-cluster-local-proto=<var>PROTO (tcp/ssl)</var></code></p>
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..13ae464ad 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;
}