diff --git a/.openvswitch.metadata b/.openvswitch.metadata index d8eac7e..8b4f154 100644 --- a/.openvswitch.metadata +++ b/.openvswitch.metadata @@ -1,6 +1,6 @@ +d34f96421a86004aa5d26ecf975edefd09f948b1 SOURCES/Pygments-1.4.tar.gz +3a11f130c63b057532ca37fe49c8967d0cbae1d5 SOURCES/Sphinx-1.2.3.tar.gz 002450621b33c5690060345b0aac25bc2426d675 SOURCES/docutils-0.12.tar.gz c4b0954cf2717fe294880c479cf5d41225ac9d87 SOURCES/openvswitch-3.2.0.tar.gz 8509a716f9f936526f64fb23f313c5a9baf2f123 SOURCES/pyelftools-0.27.tar.gz -d34f96421a86004aa5d26ecf975edefd09f948b1 SOURCES/Pygments-1.4.tar.gz -3a11f130c63b057532ca37fe49c8967d0cbae1d5 SOURCES/Sphinx-1.2.3.tar.gz a6b5bf45bb8f65c704310f9fe592081af9d94aab SOURCES/dpdk-22.11.1.tar.xz diff --git a/SOURCES/openvswitch-3.2.0.patch b/SOURCES/openvswitch-3.2.0.patch index 67e6ee4..3420109 100644 --- a/SOURCES/openvswitch-3.2.0.patch +++ b/SOURCES/openvswitch-3.2.0.patch @@ -1,3 +1,13 @@ +diff --git a/.ci/dpdk-prepare.sh b/.ci/dpdk-prepare.sh +index f7e6215dda..4424f9eb97 100755 +--- a/.ci/dpdk-prepare.sh ++++ b/.ci/dpdk-prepare.sh +@@ -8,4 +8,4 @@ set -ev + # https://github.com/pypa/pip/issues/10655 + pip3 install --disable-pip-version-check --user wheel + pip3 install --disable-pip-version-check --user pyelftools +-pip3 install --user 'meson==0.53.2' ++pip3 install --user 'meson>=1.4,<1.5' diff --git a/.ci/linux-build.sh b/.ci/linux-build.sh index 99850a9434..8227a57487 100755 --- a/.ci/linux-build.sh @@ -13,8 +23,21 @@ index 99850a9434..8227a57487 100755 if [ "$CC" = "clang" ]; then CFLAGS_FOR_OVS="${CFLAGS_FOR_OVS} -Wno-error=unused-command-line-argument" elif [ "$M32" ]; then +diff --git a/.ci/linux-prepare.sh b/.ci/linux-prepare.sh +index c28b6819a3..133e8d9673 100755 +--- a/.ci/linux-prepare.sh ++++ b/.ci/linux-prepare.sh +@@ -23,7 +23,7 @@ cd .. + # https://github.com/pypa/pip/issues/10655 + pip3 install --disable-pip-version-check --user wheel + pip3 install --disable-pip-version-check --user \ +- flake8 'hacking>=3.0' netaddr pyparsing sphinx setuptools ++ flake8 netaddr pyparsing sphinx setuptools + + # Install python test dependencies + pip3 install -r python/test_requirements.txt diff --git a/.cirrus.yml b/.cirrus.yml -index 48931fa085..d8a9722809 100644 +index 48931fa085..8db385f002 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -2,8 +2,8 @@ freebsd_build_task: @@ -22,16 +45,26 @@ index 48931fa085..d8a9722809 100644 freebsd_instance: matrix: - image_family: freebsd-12-4-snap - image_family: freebsd-13-2-snap +- image_family: freebsd-13-2-snap ++ image_family: freebsd-13-3-snap + image_family: freebsd-14-0-snap cpu: 4 memory: 4G diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml -index 47d239f108..8d4815b362 100644 +index 47d239f108..565058cec6 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml -@@ -8,16 +8,16 @@ jobs: +@@ -2,22 +2,25 @@ name: Build and Test + + on: [push, pull_request] + ++env: ++ python_default: 3.12 ++ + jobs: + build-dpdk: + env: dependencies: gcc libnuma-dev ninja-build CC: gcc DPDK_GIT: https://dpdk.org/git/dpdk-stable @@ -51,7 +84,7 @@ index 47d239f108..8d4815b362 100644 - name: update PATH run: | -@@ -45,14 +45,14 @@ jobs: +@@ -45,16 +48,16 @@ jobs: - name: cache id: dpdk_cache @@ -66,9 +99,12 @@ index 47d239f108..8d4815b362 100644 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: '3.9' +- python-version: '3.9' ++ python-version: ${{ env.python_default }} -@@ -85,10 +85,11 @@ jobs: + - name: update APT cache + if: steps.dpdk_cache.outputs.cache-hit != 'true' +@@ -85,10 +88,11 @@ jobs: LIBS: ${{ matrix.libs }} M32: ${{ matrix.m32 }} OPTS: ${{ matrix.opts }} @@ -81,7 +117,7 @@ index 47d239f108..8d4815b362 100644 timeout-minutes: 30 strategy: -@@ -100,6 +101,11 @@ jobs: +@@ -100,6 +104,11 @@ jobs: - compiler: clang opts: --disable-ssl @@ -93,7 +129,7 @@ index 47d239f108..8d4815b362 100644 - compiler: gcc testsuite: test - compiler: clang -@@ -160,7 +166,7 @@ jobs: +@@ -160,7 +169,7 @@ jobs: steps: - name: checkout @@ -102,14 +138,15 @@ index 47d239f108..8d4815b362 100644 - name: update PATH run: | -@@ -168,13 +174,13 @@ jobs: +@@ -168,13 +177,13 @@ jobs: echo "$HOME/.local/bin" >> $GITHUB_PATH - name: set up python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: '3.9' +- python-version: '3.9' ++ python-version: ${{ env.python_default }} - name: cache if: matrix.dpdk != '' || matrix.dpdk_shared != '' @@ -118,7 +155,7 @@ index 47d239f108..8d4815b362 100644 with: path: dpdk-dir key: ${{ needs.build-dpdk.outputs.dpdk_key }} -@@ -191,6 +197,14 @@ jobs: +@@ -191,6 +200,14 @@ jobs: if: matrix.m32 != '' run: sudo apt install -y gcc-multilib @@ -133,7 +170,7 @@ index 47d239f108..8d4815b362 100644 - name: prepare run: ./.ci/linux-prepare.sh -@@ -200,9 +214,9 @@ jobs: +@@ -200,9 +217,9 @@ jobs: - name: copy logs on failure if: failure() || cancelled() run: | @@ -145,7 +182,7 @@ index 47d239f108..8d4815b362 100644 # So, we're just archiving everything here to avoid any issues. mkdir logs cp config.log ./logs/ -@@ -211,7 +225,7 @@ jobs: +@@ -211,7 +228,7 @@ jobs: - name: upload logs on failure if: failure() || cancelled() @@ -154,7 +191,7 @@ index 47d239f108..8d4815b362 100644 with: name: logs-linux-${{ join(matrix.*, '-') }} path: logs.tgz -@@ -230,13 +244,13 @@ jobs: +@@ -230,15 +247,15 @@ jobs: steps: - name: checkout @@ -168,9 +205,12 @@ index 47d239f108..8d4815b362 100644 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: '3.9' +- python-version: '3.9' ++ python-version: ${{ env.python_default }} - name: install dependencies -@@ -247,7 +261,7 @@ jobs: + run: brew install automake libtool + - name: prepare +@@ -247,7 +264,7 @@ jobs: run: ./.ci/osx-build.sh - name: upload logs on failure if: failure() @@ -179,7 +219,7 @@ index 47d239f108..8d4815b362 100644 with: name: logs-osx-clang---disable-ssl path: config.log -@@ -271,7 +285,7 @@ jobs: +@@ -271,7 +288,7 @@ jobs: steps: - name: checkout @@ -188,7 +228,7 @@ index 47d239f108..8d4815b362 100644 - name: update PATH run: | -@@ -293,7 +307,7 @@ jobs: +@@ -293,7 +310,7 @@ jobs: run: ./.ci/linux-build.sh - name: upload deb packages @@ -197,7 +237,7 @@ index 47d239f108..8d4815b362 100644 with: name: deb-packages-${{ matrix.dpdk }}-dpdk path: '/home/runner/work/ovs/*.deb' -@@ -301,7 +315,7 @@ jobs: +@@ -301,7 +318,7 @@ jobs: build-linux-rpm: name: linux rpm fedora runs-on: ubuntu-latest @@ -206,7 +246,7 @@ index 47d239f108..8d4815b362 100644 timeout-minutes: 30 strategy: -@@ -309,7 +323,7 @@ jobs: +@@ -309,7 +326,7 @@ jobs: steps: - name: checkout @@ -215,7 +255,7 @@ index 47d239f108..8d4815b362 100644 - name: install dependencies run: | dnf install -y rpm-build dnf-plugins-core -@@ -328,7 +342,7 @@ jobs: +@@ -328,7 +345,7 @@ jobs: run: dnf install -y rpm/rpmbuild/RPMS/*/*.rpm - name: upload rpm packages @@ -312,6 +352,22 @@ index 63a0ebb23b..27df48493e 100644 $ cd $DPDK_DIR #. Configure and install DPDK using Meson +diff --git a/Documentation/intro/install/general.rst b/Documentation/intro/install/general.rst +index 19e360d47c..7eb3a5d370 100644 +--- a/Documentation/intro/install/general.rst ++++ b/Documentation/intro/install/general.rst +@@ -176,10 +176,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) + + - the python packages listed in "python/test_requirements.txt" (compatible + with pip). If they are installed, the pytest-based Python unit tests will diff --git a/Documentation/ref/ovs-actions.7.rst b/Documentation/ref/ovs-actions.7.rst index d138956556..36adcc5db2 100644 --- a/Documentation/ref/ovs-actions.7.rst @@ -348,7 +404,7 @@ index 77130c6e01..77f44bd765 100644 +sphinx>=1.1 ovs_sphinx_theme>=1.0,<1.1 diff --git a/Makefile.am b/Makefile.am -index db341504d3..94f488d183 100644 +index db341504d3..0b7c832469 100644 --- a/Makefile.am +++ b/Makefile.am @@ -84,6 +84,7 @@ EXTRA_DIST = \ @@ -368,7 +424,23 @@ index db341504d3..94f488d183 100644 if grep warning: $@.tmp; then error=:; fi; \ rm -f $@.tmp; \ done; \ -@@ -415,7 +416,7 @@ endif +@@ -399,23 +400,17 @@ ALL_LOCAL += flake8-check + # F811 redefinition of unused from line (only from flake8 v2.0) + # D*** -- warnings from flake8-docstrings plugin + # H*** -- warnings from flake8 hacking plugin (custom style checks beyond PEP8) +-# H231 Python 3.x incompatible 'except x,y:' construct +-# H232 Python 3.x incompatible octal 077 should be written as 0o77 +-# H233 Python 3.x incompatible use of print operator +-# H238 old style class declaration, use new style (inherit from `object`) +-FLAKE8_SELECT = H231,H232,H233,H238 + FLAKE8_IGNORE = E121,E123,E125,E126,E127,E128,E129,E131,E203,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 CLEANFILES += flake8-check -include manpages.mk @@ -1488,6 +1560,43 @@ index cf009f8264..52614a5ac0 100644 #if __GNUC__ && !__CHECKER__ #define OVS_UNUSED __attribute__((__unused__)) #define OVS_PRINTF_FORMAT(FMT, ARG1) __attribute__((__format__(printf, FMT, ARG1))) +diff --git a/ipsec/ovs-monitor-ipsec.in b/ipsec/ovs-monitor-ipsec.in +index 7945162f9f..bc7ac55237 100755 +--- a/ipsec/ovs-monitor-ipsec.in ++++ b/ipsec/ovs-monitor-ipsec.in +@@ -457,14 +457,30 @@ conn prevent_unencrypted_vxlan + CERTKEY_PREFIX = "ovs_certkey_" + + def __init__(self, libreswan_root_prefix, args): ++ # Collect version infromation ++ self.IPSEC = libreswan_root_prefix + "/usr/sbin/ipsec" ++ proc = subprocess.Popen([self.IPSEC, "--version"], ++ stdout=subprocess.PIPE, ++ encoding="latin1") ++ pout, perr = proc.communicate() ++ ++ v = re.match("^Libreswan (.*)$", pout) ++ try: ++ version = int(v.group(1).split(".")[0]) ++ except: ++ version = 0 ++ ++ if version >= 4: ++ ipsec_d = args.ipsec_d if args.ipsec_d else "/var/lib/ipsec/nss" ++ else: ++ ipsec_d = args.ipsec_d if args.ipsec_d else "/etc/ipsec.d" ++ + ipsec_conf = args.ipsec_conf if args.ipsec_conf else "/etc/ipsec.conf" +- ipsec_d = args.ipsec_d if args.ipsec_d else "/etc/ipsec.d" + ipsec_secrets = (args.ipsec_secrets if args.ipsec_secrets + else "/etc/ipsec.secrets") + ipsec_ctl = (args.ipsec_ctl if args.ipsec_ctl + else "/run/pluto/pluto.ctl") + +- self.IPSEC = libreswan_root_prefix + "/usr/sbin/ipsec" + self.IPSEC_CONF = libreswan_root_prefix + ipsec_conf + self.IPSEC_SECRETS = libreswan_root_prefix + ipsec_secrets + self.IPSEC_D = "sql:" + libreswan_root_prefix + ipsec_d diff --git a/lib/automake.mk b/lib/automake.mk index e64ee76ce7..1be13a420a 100644 --- a/lib/automake.mk @@ -1691,7 +1800,7 @@ index 89cb2704a6..2149fdc73a 100644 conn->expiration = now + val * 1000; } diff --git a/lib/conntrack.c b/lib/conntrack.c -index 5f1176d333..592bbaa3e1 100644 +index 5f1176d333..069b069e70 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -103,7 +103,7 @@ static enum ct_update_res conn_update(struct conntrack *ct, struct conn *conn, @@ -2252,7 +2361,18 @@ index 5f1176d333..592bbaa3e1 100644 delete_conn__(conn); } -@@ -2667,15 +2580,18 @@ static void +@@ -2654,7 +2567,9 @@ tuple_to_conn_key(const struct ct_dpif_tuple *tuple, uint16_t zone, + key->src.icmp_type = tuple->icmp_type; + key->src.icmp_code = tuple->icmp_code; + key->dst.icmp_id = tuple->icmp_id; +- key->dst.icmp_type = reverse_icmp_type(tuple->icmp_type); ++ key->dst.icmp_type = (tuple->ip_proto == IPPROTO_ICMP) ++ ? reverse_icmp_type(tuple->icmp_type) ++ : reverse_icmp6_type(tuple->icmp_type); + key->dst.icmp_code = tuple->icmp_code; + } else { + key->src.port = tuple->src_port; +@@ -2667,15 +2582,18 @@ static void conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry, long long now) { @@ -2274,7 +2394,7 @@ index 5f1176d333..592bbaa3e1 100644 ovs_mutex_lock(&conn->lock); entry->mark = conn->mark; -@@ -2683,7 +2599,7 @@ conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry, +@@ -2683,7 +2601,7 @@ conn_to_ct_dpif_entry(const struct conn *conn, struct ct_dpif_entry *entry, long long expiration = conn_expiration(conn) - now; @@ -2283,7 +2403,7 @@ index 5f1176d333..592bbaa3e1 100644 if (class->conn_get_protoinfo) { class->conn_get_protoinfo(conn, &entry->protoinfo); } -@@ -2716,30 +2632,29 @@ conntrack_dump_start(struct conntrack *ct, struct conntrack_dump *dump, +@@ -2716,30 +2634,29 @@ conntrack_dump_start(struct conntrack *ct, struct conntrack_dump *dump, dump->ct = ct; *ptot_bkts = 1; /* Need to clean up the callers. */ @@ -2323,7 +2443,7 @@ index 5f1176d333..592bbaa3e1 100644 conn_to_ct_dpif_entry(conn, entry, now); return 0; } -@@ -2823,14 +2738,15 @@ conntrack_exp_dump_done(struct conntrack_dump *dump OVS_UNUSED) +@@ -2823,14 +2740,15 @@ conntrack_exp_dump_done(struct conntrack_dump *dump OVS_UNUSED) int conntrack_flush(struct conntrack *ct, const uint16_t *zone) { @@ -2343,7 +2463,7 @@ index 5f1176d333..592bbaa3e1 100644 conn_clean(ct, conn); } } -@@ -2842,18 +2758,18 @@ int +@@ -2842,18 +2760,18 @@ int conntrack_flush_tuple(struct conntrack *ct, const struct ct_dpif_tuple *tuple, uint16_t zone) { @@ -2365,7 +2485,7 @@ index 5f1176d333..592bbaa3e1 100644 error = ENOENT; } -@@ -2996,50 +2912,54 @@ expectation_create(struct conntrack *ct, ovs_be16 dst_port, +@@ -2996,50 +2914,54 @@ expectation_create(struct conntrack *ct, ovs_be16 dst_port, const struct conn *parent_conn, bool reply, bool src_ip_wc, bool skip_nat) { @@ -2432,7 +2552,7 @@ index 5f1176d333..592bbaa3e1 100644 sizeof alg_exp_node->parent_key); /* Take the write lock here because it is almost 100% * likely that the lookup will fail and -@@ -3291,12 +3211,16 @@ process_ftp_ctl_v4(struct conntrack *ct, +@@ -3291,12 +3213,16 @@ process_ftp_ctl_v4(struct conntrack *ct, switch (mode) { case CT_FTP_MODE_ACTIVE: @@ -2453,7 +2573,7 @@ index 5f1176d333..592bbaa3e1 100644 break; case CT_TFTP_MODE: default: -@@ -3328,7 +3252,7 @@ skip_ipv6_digits(char *str) +@@ -3328,7 +3254,7 @@ skip_ipv6_digits(char *str) static enum ftp_ctl_pkt process_ftp_ctl_v6(struct conntrack *ct, struct dp_packet *pkt, @@ -2462,7 +2582,7 @@ index 5f1176d333..592bbaa3e1 100644 union ct_addr *v6_addr_rep, char **ftp_data_start, size_t *addr_offset_from_ftp_data_start, size_t *addr_size, enum ct_alg_mode *mode) -@@ -3396,24 +3320,25 @@ process_ftp_ctl_v6(struct conntrack *ct, +@@ -3396,24 +3322,25 @@ process_ftp_ctl_v6(struct conntrack *ct, switch (*mode) { case CT_FTP_MODE_ACTIVE: @@ -2492,7 +2612,7 @@ index 5f1176d333..592bbaa3e1 100644 !!(pkt->md.ct_state & CS_REPLY_DIR), false, false); return CT_FTP_CTL_INTEREST; } -@@ -3571,7 +3496,8 @@ handle_tftp_ctl(struct conntrack *ct, +@@ -3571,7 +3498,8 @@ handle_tftp_ctl(struct conntrack *ct, long long now OVS_UNUSED, enum ftp_ctl_pkt ftp_ctl OVS_UNUSED, bool nat OVS_UNUSED) { @@ -2689,7 +2809,7 @@ index bdd12f6a7b..ac72a44bce 100644

diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c -index 8f1361e21f..6e30f2cc3b 100644 +index 8f1361e21f..fe82d6dd02 100644 --- a/lib/netdev-dpdk.c +++ b/lib/netdev-dpdk.c @@ -1312,6 +1312,16 @@ dpdk_eth_dev_init(struct netdev_dpdk *dev) @@ -2709,7 +2829,33 @@ index 8f1361e21f..6e30f2cc3b 100644 if (info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_IPV4_CKSUM) { dev->hw_ol_features |= NETDEV_TX_IPV4_CKSUM_OFFLOAD; } else { -@@ -2431,6 +2441,7 @@ netdev_dpdk_prep_hwol_packet(struct netdev_dpdk *dev, struct rte_mbuf *mbuf) +@@ -2248,17 +2258,16 @@ netdev_dpdk_set_config(struct netdev *netdev, const struct smap *args, + struct eth_addr mac; + + if (!dpdk_port_is_representor(dev)) { +- VLOG_WARN_BUF(errp, "'%s' is trying to set the VF MAC '%s' " +- "but 'options:dpdk-vf-mac' is only supported for " +- "VF representors.", +- netdev_get_name(netdev), vf_mac); ++ VLOG_WARN("'%s' is trying to set the VF MAC '%s' " ++ "but 'options:dpdk-vf-mac' is only supported for " ++ "VF representors.", ++ netdev_get_name(netdev), vf_mac); + } else if (!eth_addr_from_string(vf_mac, &mac)) { +- VLOG_WARN_BUF(errp, "interface '%s': cannot parse VF MAC '%s'.", +- netdev_get_name(netdev), vf_mac); ++ VLOG_WARN("interface '%s': cannot parse VF MAC '%s'.", ++ netdev_get_name(netdev), vf_mac); + } else if (eth_addr_is_multicast(mac)) { +- VLOG_WARN_BUF(errp, +- "interface '%s': cannot set VF MAC to multicast " +- "address '%s'.", netdev_get_name(netdev), vf_mac); ++ VLOG_WARN("interface '%s': cannot set VF MAC to multicast " ++ "address '%s'.", netdev_get_name(netdev), vf_mac); + } else if (!eth_addr_equals(dev->requested_hwaddr, mac)) { + dev->requested_hwaddr = mac; + netdev_request_reconfigure(netdev); +@@ -2431,6 +2440,7 @@ netdev_dpdk_prep_hwol_packet(struct netdev_dpdk *dev, struct rte_mbuf *mbuf) if (!(mbuf->ol_flags & (RTE_MBUF_F_TX_IP_CKSUM | RTE_MBUF_F_TX_L4_MASK | RTE_MBUF_F_TX_TCP_SEG))) { @@ -2717,7 +2863,7 @@ index 8f1361e21f..6e30f2cc3b 100644 return true; } -@@ -2487,6 +2498,35 @@ netdev_dpdk_prep_hwol_batch(struct netdev_dpdk *dev, struct rte_mbuf **pkts, +@@ -2487,6 +2497,35 @@ netdev_dpdk_prep_hwol_batch(struct netdev_dpdk *dev, struct rte_mbuf **pkts, return cnt; } @@ -2753,7 +2899,7 @@ index 8f1361e21f..6e30f2cc3b 100644 /* Tries to transmit 'pkts' to txq 'qid' of device 'dev'. Takes ownership of * 'pkts', even in case of failure. * -@@ -2503,6 +2543,8 @@ netdev_dpdk_eth_tx_burst(struct netdev_dpdk *dev, int qid, +@@ -2503,6 +2542,8 @@ netdev_dpdk_eth_tx_burst(struct netdev_dpdk *dev, int qid, VLOG_WARN_RL(&rl, "%s: Output batch contains invalid packets. " "Only %u/%u are valid: %s", netdev_get_name(&dev->up), nb_tx_prep, cnt, rte_strerror(rte_errno)); @@ -3049,6 +3195,54 @@ index 4fcde9ba1e..492bfcffb8 100644 nl_msg_put_be16(buf, CTA_PROTO_SRC_PORT, tuple->src_port); nl_msg_put_be16(buf, CTA_PROTO_DST_PORT, tuple->dst_port); } else { +diff --git a/lib/netlink-protocol.h b/lib/netlink-protocol.h +index 6eaa7035a4..e4bb28ac9f 100644 +--- a/lib/netlink-protocol.h ++++ b/lib/netlink-protocol.h +@@ -155,6 +155,11 @@ enum { + #define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER) + #endif + ++/* Introduced in v4.4. */ ++#ifndef NLM_F_DUMP_FILTERED ++#define NLM_F_DUMP_FILTERED 0x20 ++#endif ++ + /* These were introduced all together in 2.6.14. (We want our programs to + * support the newer kernel features even if compiled with older headers.) */ + #ifndef NETLINK_ADD_MEMBERSHIP +@@ -168,6 +173,11 @@ enum { + #define NETLINK_LISTEN_ALL_NSID 8 + #endif + ++/* Strict checking of netlink arguments introduced in Linux kernel v4.20. */ ++#ifndef NETLINK_GET_STRICT_CHK ++#define NETLINK_GET_STRICT_CHK 12 ++#endif ++ + /* These were introduced all together in 2.6.23. (We want our programs to + * support the newer kernel features even if compiled with older headers.) */ + #ifndef CTRL_ATTR_MCAST_GRP_MAX +diff --git a/lib/netlink-socket.c b/lib/netlink-socket.c +index 80da20d9f0..5cb1fc89ae 100644 +--- a/lib/netlink-socket.c ++++ b/lib/netlink-socket.c +@@ -205,6 +205,15 @@ nl_sock_create(int protocol, struct nl_sock **sockp) + } + } + ++ /* Strict checking only supported for NETLINK_ROUTE. */ ++ if (protocol == NETLINK_ROUTE ++ && setsockopt(sock->fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK, ++ &one, sizeof one) < 0) { ++ VLOG_RL(&rl, errno == ENOPROTOOPT ? VLL_DBG : VLL_WARN, ++ "netlink: could not enable strict checking (%s)", ++ ovs_strerror(errno)); ++ } ++ + retval = get_socket_rcvbuf(sock->fd); + if (retval < 0) { + retval = -retval; diff --git a/lib/odp-util.c b/lib/odp-util.c index 3eb2c3cb98..9306c9b4d4 100644 --- a/lib/odp-util.c @@ -3149,6 +3343,25 @@ index a956754f2d..f9bd3b7f9c 100644 } i++; } +diff --git a/lib/ofpbuf.c b/lib/ofpbuf.c +index d3d42b4148..232ebeb97b 100644 +--- a/lib/ofpbuf.c ++++ b/lib/ofpbuf.c +@@ -197,12 +197,12 @@ ofpbuf_clone_with_headroom(const struct ofpbuf *b, size_t headroom) + struct ofpbuf *new_buffer; + + new_buffer = ofpbuf_clone_data_with_headroom(b->data, b->size, headroom); +- if (b->header) { ++ if (new_buffer->data && b->header) { + ptrdiff_t header_offset = (char *) b->header - (char *) b->data; + + new_buffer->header = (char *) new_buffer->data + header_offset; + } +- if (b->msg) { ++ if (new_buffer->data && b->msg) { + ptrdiff_t msg_offset = (char *) b->msg - (char *) b->data; + + new_buffer->msg = (char *) new_buffer->data + msg_offset; diff --git a/lib/ovs-atomic.h b/lib/ovs-atomic.h index ab9ce6b2e0..f140d25feb 100644 --- a/lib/ovs-atomic.h @@ -3272,6 +3485,172 @@ index 9777efea33..688fe56337 100644 #ifdef __cplusplus } #endif +diff --git a/lib/route-table.c b/lib/route-table.c +index 9927dcc185..f1fe32714e 100644 +--- a/lib/route-table.c ++++ b/lib/route-table.c +@@ -26,6 +26,7 @@ + #include + #include + ++#include "coverage.h" + #include "hash.h" + #include "netdev.h" + #include "netlink.h" +@@ -44,6 +45,8 @@ + + VLOG_DEFINE_THIS_MODULE(route_table); + ++COVERAGE_DEFINE(route_table_dump); ++ + struct route_data { + /* Copied from struct rtmsg. */ + unsigned char rtm_dst_len; +@@ -80,7 +83,7 @@ static struct nln_notifier *name_notifier = NULL; + + static bool route_table_valid = false; + +-static int route_table_reset(void); ++static void route_table_reset(void); + static void route_table_handle_msg(const struct route_table_msg *); + static int route_table_parse(struct ofpbuf *, struct route_table_msg *); + static void route_table_change(const struct route_table_msg *, void *); +@@ -153,26 +156,22 @@ route_table_wait(void) + ovs_mutex_unlock(&route_table_mutex); + } + +-static int +-route_table_reset(void) ++static bool ++route_table_dump_one_table(unsigned char id) + { +- struct nl_dump dump; +- struct rtgenmsg *rtgenmsg; + uint64_t reply_stub[NL_DUMP_BUFSIZE / 8]; + struct ofpbuf request, reply, buf; +- +- route_map_clear(); +- netdev_get_addrs_list_flush(); +- route_table_valid = true; +- rt_change_seq++; ++ struct rtmsg *rq_msg; ++ bool filtered = true; ++ struct nl_dump dump; + + ofpbuf_init(&request, 0); + +- nl_msg_put_nlmsghdr(&request, sizeof *rtgenmsg, RTM_GETROUTE, +- NLM_F_REQUEST); ++ nl_msg_put_nlmsghdr(&request, sizeof *rq_msg, RTM_GETROUTE, NLM_F_REQUEST); + +- rtgenmsg = ofpbuf_put_zeros(&request, sizeof *rtgenmsg); +- rtgenmsg->rtgen_family = AF_UNSPEC; ++ rq_msg = ofpbuf_put_zeros(&request, sizeof *rq_msg); ++ rq_msg->rtm_family = AF_UNSPEC; ++ rq_msg->rtm_table = id; + + nl_dump_start(&dump, NETLINK_ROUTE, &request); + ofpbuf_uninit(&request); +@@ -182,12 +181,43 @@ route_table_reset(void) + struct route_table_msg msg; + + if (route_table_parse(&reply, &msg)) { ++ struct nlmsghdr *nlmsghdr = nl_msg_nlmsghdr(&reply); ++ ++ /* Older kernels do not support filtering. */ ++ if (!(nlmsghdr->nlmsg_flags & NLM_F_DUMP_FILTERED)) { ++ filtered = false; ++ } + route_table_handle_msg(&msg); + } + } + ofpbuf_uninit(&buf); ++ nl_dump_done(&dump); ++ ++ return filtered; ++} ++ ++static void ++route_table_reset(void) ++{ ++ unsigned char tables[] = { ++ RT_TABLE_DEFAULT, ++ RT_TABLE_MAIN, ++ RT_TABLE_LOCAL, ++ }; + +- return nl_dump_done(&dump); ++ route_map_clear(); ++ netdev_get_addrs_list_flush(); ++ route_table_valid = true; ++ rt_change_seq++; ++ ++ COVERAGE_INC(route_table_dump); ++ ++ for (size_t i = 0; i < ARRAY_SIZE(tables); i++) { ++ if (!route_table_dump_one_table(tables[i])) { ++ /* Got unfiltered reply, no need to dump further. */ ++ break; ++ } ++ } + } + + /* Return RTNLGRP_IPV4_ROUTE or RTNLGRP_IPV6_ROUTE on success, 0 on parse +@@ -203,6 +233,7 @@ route_table_parse(struct ofpbuf *buf, struct route_table_msg *change) + [RTA_GATEWAY] = { .type = NL_A_U32, .optional = true }, + [RTA_MARK] = { .type = NL_A_U32, .optional = true }, + [RTA_PREFSRC] = { .type = NL_A_U32, .optional = true }, ++ [RTA_TABLE] = { .type = NL_A_U32, .optional = true }, + }; + + static const struct nl_policy policy6[] = { +@@ -211,6 +242,7 @@ route_table_parse(struct ofpbuf *buf, struct route_table_msg *change) + [RTA_MARK] = { .type = NL_A_U32, .optional = true }, + [RTA_GATEWAY] = { .type = NL_A_IPV6, .optional = true }, + [RTA_PREFSRC] = { .type = NL_A_IPV6, .optional = true }, ++ [RTA_TABLE] = { .type = NL_A_U32, .optional = true }, + }; + + struct nlattr *attrs[ARRAY_SIZE(policy)]; +@@ -232,6 +264,7 @@ route_table_parse(struct ofpbuf *buf, struct route_table_msg *change) + + if (parsed) { + const struct nlmsghdr *nlmsg; ++ uint32_t table_id; + int rta_oif; /* Output interface index. */ + + nlmsg = buf->data; +@@ -247,6 +280,19 @@ route_table_parse(struct ofpbuf *buf, struct route_table_msg *change) + rtm->rtm_type != RTN_LOCAL) { + change->relevant = false; + } ++ ++ table_id = rtm->rtm_table; ++ if (attrs[RTA_TABLE]) { ++ table_id = nl_attr_get_u32(attrs[RTA_TABLE]); ++ } ++ /* Do not consider changes in non-standard routing tables. */ ++ if (table_id ++ && table_id != RT_TABLE_DEFAULT ++ && table_id != RT_TABLE_MAIN ++ && table_id != RT_TABLE_LOCAL) { ++ change->relevant = false; ++ } ++ + change->nlmsg_type = nlmsg->nlmsg_type; + change->rd.rtm_dst_len = rtm->rtm_dst_len + (ipv4 ? 96 : 0); + change->rd.local = rtm->rtm_type == RTN_LOCAL; +@@ -312,7 +358,9 @@ static void + route_table_change(const struct route_table_msg *change OVS_UNUSED, + void *aux OVS_UNUSED) + { +- route_table_valid = false; ++ if (!change || change->relevant) { ++ route_table_valid = false; ++ } + } + + static void diff --git a/lib/rstp.c b/lib/rstp.c index 2f01966f79..90e8094599 100644 --- a/lib/rstp.c @@ -3558,10 +3937,18 @@ index 527e2f17ed..4fbe85018e 100644 void diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c -index 04b583f816..292500f215 100644 +index 04b583f816..7d324e7e0a 100644 --- a/ofproto/ofproto-dpif-upcall.c +++ b/ofproto/ofproto-dpif-upcall.c -@@ -988,7 +988,7 @@ udpif_revalidator(void *arg) +@@ -58,6 +58,7 @@ COVERAGE_DEFINE(handler_duplicate_upcall); + COVERAGE_DEFINE(revalidate_missed_dp_flow); + COVERAGE_DEFINE(ukey_dp_change); + COVERAGE_DEFINE(ukey_invalid_stat_reset); ++COVERAGE_DEFINE(ukey_replace_contention); + COVERAGE_DEFINE(upcall_flow_limit_hit); + COVERAGE_DEFINE(upcall_flow_limit_kill); + COVERAGE_DEFINE(upcall_ukey_contention); +@@ -988,7 +989,7 @@ udpif_revalidator(void *arg) udpif->reval_exit = latch_is_set(&udpif->exit_latch); start_time = time_msec(); @@ -3570,7 +3957,7 @@ index 04b583f816..292500f215 100644 bool terse_dump; terse_dump = udpif_use_ufid(udpif); -@@ -998,10 +998,15 @@ udpif_revalidator(void *arg) +@@ -998,10 +999,15 @@ udpif_revalidator(void *arg) } } @@ -3587,6 +3974,44 @@ index 04b583f816..292500f215 100644 } if (udpif->reval_exit) { +@@ -1415,8 +1421,6 @@ upcall_cb(const struct dp_packet *packet, const struct flow *flow, ovs_u128 *ufi + } + + if (upcall.ukey && !ukey_install(udpif, upcall.ukey)) { +- static struct vlog_rate_limit rll = VLOG_RATE_LIMIT_INIT(1, 1); +- VLOG_WARN_RL(&rll, "upcall_cb failure: ukey installation fails"); + error = ENOSPC; + } + out: +@@ -1914,15 +1918,15 @@ try_ukey_replace(struct umap *umap, struct udpif_key *old_ukey, + transition_ukey(old_ukey, UKEY_DELETED); + transition_ukey(new_ukey, UKEY_VISIBLE); + replaced = true; ++ COVERAGE_INC(upcall_ukey_replace); ++ } else { ++ COVERAGE_INC(handler_duplicate_upcall); + } + ovs_mutex_unlock(&old_ukey->mutex); +- } +- +- if (replaced) { +- COVERAGE_INC(upcall_ukey_replace); + } else { +- COVERAGE_INC(handler_duplicate_upcall); ++ COVERAGE_INC(ukey_replace_contention); + } ++ + return replaced; + } + +@@ -2941,6 +2945,7 @@ revalidator_sweep__(struct revalidator *revalidator, bool purge) + /* Handler threads could be holding a ukey lock while it installs a + * new flow, so don't hang around waiting for access to it. */ + if (ovs_mutex_trylock(&ukey->mutex)) { ++ COVERAGE_INC(upcall_ukey_contention); + continue; + } + ukey_state = ukey->state; @@ -3195,11 +3200,19 @@ upcall_unixctl_purge(struct unixctl_conn *conn, int argc OVS_UNUSED, struct udpif *udpif; @@ -3621,7 +4046,7 @@ index 9224ee2e6d..2e1fcb3a6f 100644 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "xcache LEARN action execution failed."); diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c -index 47ea0f47e7..078d1bd96b 100644 +index 47ea0f47e7..94da7c09d5 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -1615,7 +1615,8 @@ xlate_lookup_ofproto_(const struct dpif_backer *backer, @@ -3671,7 +4096,112 @@ index 47ea0f47e7..078d1bd96b 100644 } err = tnl_route_lookup_flow(ctx, flow, &d_ip6, &s_ip6, &out_dev); -@@ -5700,8 +5712,16 @@ xlate_learn_action(struct xlate_ctx *ctx, const struct ofpact_learn *learn) +@@ -5026,10 +5038,37 @@ put_controller_user_action(struct xlate_ctx *ctx, + bool dont_send, bool continuation, + uint32_t recirc_id, int len, + enum ofp_packet_in_reason reason, ++ uint32_t provider_meter_id, + uint16_t controller_id) + { + struct user_action_cookie cookie; + ++ /* If the controller action didn't request a meter (indicated by a ++ * 'meter_id' argument other than NX_CTLR_NO_METER), see if one was ++ * configured through the "controller" virtual meter. ++ * ++ * Internally, ovs-vswitchd uses UINT32_MAX to indicate no meter is ++ * configured. */ ++ uint32_t meter_id; ++ if (provider_meter_id == UINT32_MAX) { ++ meter_id = ctx->xbridge->ofproto->up.controller_meter_id; ++ } else { ++ meter_id = provider_meter_id; ++ } ++ ++ size_t offset; ++ size_t ac_offset; ++ if (meter_id != UINT32_MAX) { ++ /* If controller meter is configured, generate ++ * clone(meter,userspace) action. */ ++ offset = nl_msg_start_nested(ctx->odp_actions, OVS_ACTION_ATTR_SAMPLE); ++ nl_msg_put_u32(ctx->odp_actions, OVS_SAMPLE_ATTR_PROBABILITY, ++ UINT32_MAX); ++ ac_offset = nl_msg_start_nested(ctx->odp_actions, ++ OVS_SAMPLE_ATTR_ACTIONS); ++ nl_msg_put_u32(ctx->odp_actions, OVS_ACTION_ATTR_METER, meter_id); ++ } ++ + memset(&cookie, 0, sizeof cookie); + cookie.type = USER_ACTION_COOKIE_CONTROLLER; + cookie.ofp_in_port = OFPP_NONE, +@@ -5047,6 +5086,11 @@ put_controller_user_action(struct xlate_ctx *ctx, + uint32_t pid = dpif_port_get_pid(ctx->xbridge->dpif, odp_port); + odp_put_userspace_action(pid, &cookie, sizeof cookie, ODPP_NONE, + false, ctx->odp_actions, NULL); ++ ++ if (meter_id != UINT32_MAX) { ++ nl_msg_end_nested(ctx->odp_actions, ac_offset); ++ nl_msg_end_nested(ctx->odp_actions, offset); ++ } + } + + static void +@@ -5091,32 +5135,6 @@ xlate_controller_action(struct xlate_ctx *ctx, int len, + } + recirc_refs_add(&ctx->xout->recircs, recirc_id); + +- /* If the controller action didn't request a meter (indicated by a +- * 'meter_id' argument other than NX_CTLR_NO_METER), see if one was +- * configured through the "controller" virtual meter. +- * +- * Internally, ovs-vswitchd uses UINT32_MAX to indicate no meter is +- * configured. */ +- uint32_t meter_id; +- if (provider_meter_id == UINT32_MAX) { +- meter_id = ctx->xbridge->ofproto->up.controller_meter_id; +- } else { +- meter_id = provider_meter_id; +- } +- +- size_t offset; +- size_t ac_offset; +- if (meter_id != UINT32_MAX) { +- /* If controller meter is configured, generate clone(meter, userspace) +- * action. */ +- offset = nl_msg_start_nested(ctx->odp_actions, OVS_ACTION_ATTR_SAMPLE); +- nl_msg_put_u32(ctx->odp_actions, OVS_SAMPLE_ATTR_PROBABILITY, +- UINT32_MAX); +- ac_offset = nl_msg_start_nested(ctx->odp_actions, +- OVS_SAMPLE_ATTR_ACTIONS); +- nl_msg_put_u32(ctx->odp_actions, OVS_ACTION_ATTR_METER, meter_id); +- } +- + /* Generate the datapath flows even if we don't send the packet-in + * so that debugging more closely represents normal state. */ + bool dont_send = false; +@@ -5124,12 +5142,7 @@ xlate_controller_action(struct xlate_ctx *ctx, int len, + dont_send = true; + } + put_controller_user_action(ctx, dont_send, false, recirc_id, len, +- reason, controller_id); +- +- if (meter_id != UINT32_MAX) { +- nl_msg_end_nested(ctx->odp_actions, ac_offset); +- nl_msg_end_nested(ctx->odp_actions, offset); +- } ++ reason, provider_meter_id, controller_id); + } + + /* Creates a frozen state, and allocates a unique recirc id for the given +@@ -5181,6 +5194,7 @@ finish_freezing__(struct xlate_ctx *ctx, uint8_t table) + put_controller_user_action(ctx, false, true, recirc_id, + ctx->pause->max_len, + ctx->pause->reason, ++ ctx->pause->provider_meter_id, + ctx->pause->controller_id); + } else { + if (ctx->recirc_update_dp_hash) { +@@ -5700,8 +5714,16 @@ xlate_learn_action(struct xlate_ctx *ctx, const struct ofpact_learn *learn) if (!error) { bool success = true; if (ctx->xin->allow_side_effects) { @@ -3690,10 +4220,38 @@ index 47ea0f47e7..078d1bd96b 100644 if (!ofm->temp_rule || ofm->temp_rule->state != RULE_INSERTED) { diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c -index e22ca757ac..ba5706f6ad 100644 +index e22ca757ac..ff520c150e 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c -@@ -4880,7 +4880,7 @@ packet_xlate(struct ofproto *ofproto_, struct ofproto_packet_out *opo) +@@ -3902,15 +3902,21 @@ port_query_by_name(const struct ofproto *ofproto_, const char *devname, + int error; + + if (sset_contains(&ofproto->ghost_ports, devname)) { +- const char *type = netdev_get_type_from_name(devname); +- + /* We may be called before ofproto->up.port_by_name is populated with + * the appropriate ofport. For this reason, we must get the name and +- * type from the netdev layer directly. */ +- if (type) { +- const struct ofport *ofport; ++ * type from the netdev layer directly. ++ * However, when a port deleted, the corresponding netdev is also ++ * removed from netdev_shash. netdev_get_type_from_name returns NULL ++ * in such case and we should try to get type from ofport->netdev. */ ++ const char *type = netdev_get_type_from_name(devname); ++ const struct ofport *ofport = ++ shash_find_data(&ofproto->up.port_by_name, devname); + +- ofport = shash_find_data(&ofproto->up.port_by_name, devname); ++ if (!type && ofport && ofport->netdev) { ++ type = netdev_get_type(ofport->netdev); ++ } ++ ++ if (type) { + ofproto_port->ofp_port = ofport ? ofport->ofp_port : OFPP_NONE; + ofproto_port->name = xstrdup(devname); + ofproto_port->type = xstrdup(type); +@@ -4880,7 +4886,7 @@ packet_xlate(struct ofproto *ofproto_, struct ofproto_packet_out *opo) if (entry->type == XC_LEARN) { struct ofproto_flow_mod *ofm = entry->learn.ofm; @@ -3849,6 +4407,24 @@ index 3455ed233b..80ddee78ac 100644 flow->tunnel.tp_dst = cfg->dst_port; if (!cfg->out_key_flow) { flow->tunnel.tun_id = cfg->out_key; +diff --git a/ovsdb/automake.mk b/ovsdb/automake.mk +index eba713bb6d..d484fe9deb 100644 +--- a/ovsdb/automake.mk ++++ b/ovsdb/automake.mk +@@ -114,11 +114,13 @@ $(OVSIDL_BUILT): ovsdb/ovsdb-idlc.in python/ovs/dirs.py + + # ovsdb-doc + EXTRA_DIST += ovsdb/ovsdb-doc ++FLAKE8_PYFILES += ovsdb/ovsdb-doc + OVSDB_DOC = $(run_python) $(srcdir)/ovsdb/ovsdb-doc + ovsdb/ovsdb-doc: python/ovs/dirs.py + + # ovsdb-dot + EXTRA_DIST += ovsdb/ovsdb-dot.in ovsdb/dot2pic ++FLAKE8_PYFILES += ovsdb/ovsdb-dot.in ovsdb/dot2pic + noinst_SCRIPTS += ovsdb/ovsdb-dot + CLEANFILES += ovsdb/ovsdb-dot + OVSDB_DOT = $(run_python) $(srcdir)/ovsdb/ovsdb-dot.in diff --git a/ovsdb/condition.c b/ovsdb/condition.c index 5a3eb4e8a3..4911fbf59b 100644 --- a/ovsdb/condition.c @@ -3871,6 +4447,34 @@ index 5a3eb4e8a3..4911fbf59b 100644 } } +diff --git a/ovsdb/dot2pic b/ovsdb/dot2pic +index 2f858e19d5..3db6444de6 100755 +--- a/ovsdb/dot2pic ++++ b/ovsdb/dot2pic +@@ -17,6 +17,7 @@ + import getopt + import sys + ++ + def dot2pic(src, dst): + scale = 1.0 + while True: +@@ -49,8 +50,8 @@ def dot2pic(src, dst): + dst.write("box at %f,%f wid %f height %f\n" + % (x, y, width, height)) + elif command == 'edge': +- tail = words[1] +- head = words[2] ++ # tail = words[1] ++ # head = words[2] + n = int(words[3]) + + # Extract x,y coordinates. +@@ -114,4 +115,3 @@ else: + if font_scale: + print(".ps %+d" % font_scale) + print(".PE") +- diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c index 17868f5b72..5d10f54293 100644 --- a/ovsdb/jsonrpc-server.c @@ -3896,18 +4500,524 @@ index 01091fabe7..f4a9cf8fe3 100644 &mtc->old_condition, &mtc->new_condition); ovsdb_monitor_condition_add_columns(dbmon, diff --git a/ovsdb/ovsdb-doc b/ovsdb/ovsdb-doc -index 10d0c0c134..099770d253 100755 +index 10d0c0c134..2edf487a28 100755 --- a/ovsdb/ovsdb-doc +++ b/ovsdb/ovsdb-doc -@@ -24,7 +24,7 @@ import ovs.json +@@ -14,9 +14,7 @@ + # See the License for the specific language governing permissions and + # limitations under the License. + +-from datetime import date + import getopt +-import os + import sys + import xml.dom.minidom + +@@ -24,10 +22,13 @@ import ovs.json from ovs.db import error import ovs.db.schema -from build.nroff import * -+from ovs_build_helpers.nroff import * ++from ovs_build_helpers.nroff import block_xml_to_nroff ++from ovs_build_helpers.nroff import escape_nroff_literal ++from ovs_build_helpers.nroff import text_to_nroff + + argv0 = sys.argv[0] + ++ + def typeAndConstraintsToNroff(column): + type = column.type.toEnglish(escape_nroff_literal) + constraints = column.type.constraintsToEnglish(escape_nroff_literal, +@@ -38,6 +39,7 @@ def typeAndConstraintsToNroff(column): + type += " (must be unique within table)" + return type + ++ + def columnGroupToNroff(table, groupXml, documented_columns): + introNodes = [] + columnNodes = [] +@@ -49,7 +51,10 @@ def columnGroupToNroff(table, groupXml, documented_columns): + if (columnNodes + and not (node.nodeType == node.TEXT_NODE + and node.data.isspace())): +- raise error.Error("text follows or inside : %s" % node) ++ raise error.Error( ++ "text follows or inside : %s" ++ % node ++ ) + introNodes += [node] + + summary = [] +@@ -65,15 +70,9 @@ def columnGroupToNroff(table, groupXml, documented_columns): + if node.hasAttribute('type'): + type_string = node.attributes['type'].nodeValue + type_json = ovs.json.from_string(str(type_string)) +- # py2 -> py3 means str -> bytes and unicode -> str +- try: +- if type(type_json) in (str, unicode): +- raise error.Error("%s %s:%s has invalid 'type': %s" +- % (table.name, name, key, type_json)) +- except: +- if type(type_json) in (bytes, str): +- raise error.Error("%s %s:%s has invalid 'type': %s" +- % (table.name, name, key, type_json)) ++ if type(type_json) in (bytes, str): ++ raise error.Error("%s %s:%s has invalid 'type': %s" ++ % (table.name, name, key, type_json)) + type_ = ovs.db.types.BaseType.from_json(type_json) + else: + type_ = column.type.value +@@ -91,10 +90,11 @@ def columnGroupToNroff(table, groupXml, documented_columns): + else: + if type_.type != column.type.value.type: + type_english = type_.toEnglish() ++ typeNroff += ", containing " + if type_english[0] in 'aeiou': +- typeNroff += ", containing an %s" % type_english ++ typeNroff += "an %s" % type_english + else: +- typeNroff += ", containing a %s" % type_english ++ typeNroff += "a %s" % type_english + constraints = ( + type_.constraintsToEnglish(escape_nroff_literal, + text_to_nroff)) +@@ -121,6 +121,7 @@ def columnGroupToNroff(table, groupXml, documented_columns): + raise error.Error("unknown element %s in " % node.tagName) + return summary, intro, body + ++ + def tableSummaryToNroff(summary, level=0): + s = "" + for type, name, arg in summary: +@@ -132,6 +133,7 @@ def tableSummaryToNroff(summary, level=0): + s += ".RE\n" + return s + ++ + def tableToNroff(schema, tableXml): + tableName = tableXml.attributes['name'].nodeValue + table = schema.tables[tableName] +@@ -156,20 +158,17 @@ def tableToNroff(schema, tableXml): + + return s + ++ + def docsToNroff(schemaFile, xmlFile, erFile, version=None): + schema = ovs.db.schema.DbSchema.from_json(ovs.json.from_file(schemaFile)) + doc = xml.dom.minidom.parse(xmlFile).documentElement + +- schemaDate = os.stat(schemaFile).st_mtime +- xmlDate = os.stat(xmlFile).st_mtime +- d = date.fromtimestamp(max(schemaDate, xmlDate)) +- + if doc.hasAttribute('name'): + manpage = doc.attributes['name'].nodeValue + else: + manpage = schema.name + +- if version == None: ++ if version is None: + version = "UNKNOWN" + + # Putting '\" p as the first line tells "man" that the manpage +@@ -194,7 +193,6 @@ def docsToNroff(schemaFile, xmlFile, erFile, version=None): + .PP + ''' % (manpage, schema.version, version, text_to_nroff(manpage), schema.name) + +- tables = "" + introNodes = [] + tableNodes = [] + summary = [] +@@ -237,8 +235,8 @@ Purpose + """ % (name, text_to_nroff(title)) + + if erFile: +- s += """ +-.\\" check if in troff mode (TTY) ++ s += r""" ++.\" check if in troff mode (TTY) + .if t \{ + .bp + .SH "TABLE RELATIONSHIPS" +@@ -248,8 +246,8 @@ database. Each node represents a table. Tables that are part of the + ``root set'' are shown with double borders. Each edge leads from the + table that contains it and points to the table that its value + represents. Edges are labeled with their column names, followed by a +-constraint on the number of allowed values: \\fB?\\fR for zero or one, +-\\fB*\\fR for zero or more, \\fB+\\fR for one or more. Thick lines ++constraint on the number of allowed values: \fB?\fR for zero or one, ++\fB*\fR for zero or more, \fB+\fR for one or more. Thick lines + represent strong references; thin lines represent weak references. + .RS -1in + """ +@@ -263,6 +261,7 @@ represent strong references; thin lines represent weak references. + s += tableToNroff(schema, node) + "\n" + return s + ++ + def usage(): + print("""\ + %(argv0)s: ovsdb schema documentation generator +@@ -278,6 +277,7 @@ The following options are also available: + """ % {'argv0': argv0}) + sys.exit(0) + ++ + if __name__ == "__main__": + try: + try: +diff --git a/ovsdb/ovsdb-dot.in b/ovsdb/ovsdb-dot.in +index 41b986c0ac..f1eefd49cb 100755 +--- a/ovsdb/ovsdb-dot.in ++++ b/ovsdb/ovsdb-dot.in +@@ -1,15 +1,13 @@ + #! @PYTHON3@ + +-from datetime import date + import ovs.db.error + import ovs.db.schema + import getopt +-import os +-import re + import sys argv0 = sys.argv[0] ++ + def printEdge(tableName, type, baseType, label): + if baseType.ref_table_name: + if type.n_min == 0: +@@ -31,38 +29,42 @@ def printEdge(tableName, type, baseType, label): + options['label'] = '"%s%s"' % (label, arity) + if baseType.ref_type == 'weak': + options['style'] = 'dotted' +- print ("\t%s -> %s [%s];" % ( ++ print("\t%s -> %s [%s];" % ( + tableName, + baseType.ref_table_name, +- ', '.join(['%s=%s' % (k,v) for k,v in options.items()]))) ++ ', '.join(['%s=%s' % (k, v) for k, v in options.items()]))) ++ + + def schemaToDot(schemaFile, arrows): + schema = ovs.db.schema.DbSchema.from_json(ovs.json.from_file(schemaFile)) + +- print ("digraph %s {" % schema.name) +- print ('\trankdir=LR;') +- print ('\tsize="6.5,4";') +- print ('\tmargin="0";') +- print ("\tnode [shape=box];") ++ print("digraph %s {" % schema.name) ++ print('\trankdir=LR;') ++ print('\tsize="6.5,4";') ++ print('\tmargin="0";') ++ print("\tnode [shape=box];") + if not arrows: +- print ("\tedge [dir=none, arrowhead=none, arrowtail=none];") ++ print("\tedge [dir=none, arrowhead=none, arrowtail=none];") + for tableName, table in schema.tables.items(): + options = {} + if table.is_root: + options['style'] = 'bold' +- print ("\t%s [%s];" % ( ++ print("\t%s [%s];" % ( + tableName, +- ', '.join(['%s=%s' % (k,v) for k,v in options.items()]))) ++ ', '.join(['%s=%s' % (k, v) for k, v in options.items()]))) + for columnName, column in table.columns.items(): + if column.type.value: +- printEdge(tableName, column.type, column.type.key, "%s key" % columnName) +- printEdge(tableName, column.type, column.type.value, "%s value" % columnName) ++ printEdge(tableName, column.type, column.type.key, ++ "%s key" % columnName) ++ printEdge(tableName, column.type, column.type.value, ++ "%s value" % columnName) + else: + printEdge(tableName, column.type, column.type.key, columnName) +- print ("}"); ++ print("}") ++ + + def usage(): +- print ("""\ ++ print("""\ + %(argv0)s: compiles ovsdb schemas to graphviz format + Prints a .dot file that "dot" can render to an entity-relationship diagram + usage: %(argv0)s [OPTIONS] SCHEMA +@@ -75,12 +77,13 @@ The following options are also available: + """ % {'argv0': argv0}) + sys.exit(0) + ++ + if __name__ == "__main__": + try: + try: + options, args = getopt.gnu_getopt(sys.argv[1:], 'hV', + ['no-arrows', +- 'help', 'version',]) ++ 'help', 'version']) + except getopt.GetoptError as geo: + sys.stderr.write("%s: %s\n" % (argv0, geo.msg)) + sys.exit(1) +@@ -92,7 +95,7 @@ if __name__ == "__main__": + elif key in ['-h', '--help']: + usage() + elif key in ['-V', '--version']: +- print ("ovsdb-dot (Open vSwitch) @VERSION@") ++ print("ovsdb-dot (Open vSwitch) @VERSION@") + else: + sys.exit(0) + +diff --git a/ovsdb/raft.c b/ovsdb/raft.c +index b2361b1737..2066d4869b 100644 +--- a/ovsdb/raft.c ++++ b/ovsdb/raft.c +@@ -80,6 +80,7 @@ enum raft_failure_test { + FT_STOP_RAFT_RPC, + FT_TRANSFER_LEADERSHIP, + FT_TRANSFER_LEADERSHIP_AFTER_SEND_APPEND_REQ, ++ FT_TRANSFER_LEADERSHIP_AFTER_STARTING_TO_ADD, + }; + static enum raft_failure_test failure_test; + +@@ -378,6 +379,7 @@ static void raft_get_servers_from_log(struct raft *, enum vlog_level); + static void raft_get_election_timer_from_log(struct raft *); + + static bool raft_handle_write_error(struct raft *, struct ovsdb_error *); ++static bool raft_has_uncommitted_configuration(const struct raft *); + + static void raft_run_reconfigure(struct raft *); + +@@ -1005,8 +1007,13 @@ raft_conn_update_probe_interval(struct raft *raft, struct raft_conn *r_conn) + * inactivity probe follower will just try to initiate election + * indefinitely staying in 'candidate' role. And the leader will continue + * to send heartbeats to the dead connection thinking that remote server +- * is still part of the cluster. */ +- int probe_interval = raft->election_timer + ELECTION_RANGE_MSEC; ++ * is still part of the cluster. ++ * ++ * While joining, the real value of the election timeout is not known to ++ * this server, so using the maximum. */ ++ int probe_interval = (raft->joining ? ELECTION_MAX_MSEC ++ : raft->election_timer) ++ + ELECTION_RANGE_MSEC; + + jsonrpc_session_set_probe_interval(r_conn->js, probe_interval); + } +@@ -1250,10 +1257,30 @@ raft_transfer_leadership(struct raft *raft, const char *reason) + return; + } + +- struct raft_server *s; ++ struct raft_server **servers, *s; ++ uint64_t threshold = 0; ++ size_t n = 0, start, i; ++ ++ servers = xmalloc(hmap_count(&raft->servers) * sizeof *servers); ++ + HMAP_FOR_EACH (s, hmap_node, &raft->servers) { +- if (!uuid_equals(&raft->sid, &s->sid) +- && s->phase == RAFT_PHASE_STABLE) { ++ if (uuid_equals(&raft->sid, &s->sid) ++ || s->phase != RAFT_PHASE_STABLE) { ++ continue; ++ } ++ if (s->match_index > threshold) { ++ threshold = s->match_index; ++ } ++ servers[n++] = s; ++ } ++ ++ start = n ? random_range(n) : 0; ++ ++retry: ++ for (i = 0; i < n; i++) { ++ s = servers[(start + i) % n]; ++ ++ if (s->match_index >= threshold) { + struct raft_conn *conn = raft_find_conn_by_sid(raft, &s->sid); + if (!conn) { + continue; +@@ -1269,7 +1296,10 @@ raft_transfer_leadership(struct raft *raft, const char *reason) + .term = raft->term, + } + }; +- raft_send_to_conn(raft, &rpc, conn); ++ ++ if (!raft_send_to_conn(raft, &rpc, conn)) { ++ continue; ++ } + + raft_record_note(raft, "transfer leadership", + "transferring leadership to %s because %s", +@@ -1277,6 +1307,23 @@ raft_transfer_leadership(struct raft *raft, const char *reason) + break; + } + } ++ ++ if (n && i == n && threshold) { ++ if (threshold > raft->commit_index) { ++ /* Failed to transfer to servers with the highest 'match_index'. ++ * Try other servers that are not behind the majority. */ ++ threshold = raft->commit_index; ++ } else { ++ /* Try any other server. It is safe, because they either have all ++ * the append requests queued up for them before the leadership ++ * transfer message or their connection is broken and we will not ++ * transfer anyway. */ ++ threshold = 0; ++ } ++ goto retry; ++ } ++ ++ free(servers); + } + + /* Send a RemoveServerRequest to the rest of the servers in the cluster. +@@ -2649,15 +2696,22 @@ raft_become_follower(struct raft *raft) + * new configuration. Our AppendEntries processing will properly update + * the server configuration later, if necessary. + * ++ * However, since we're sending replies about a failure to add, those new ++ * servers has to be cleaned up. Otherwise, they will stuck in a 'CATCHUP' ++ * phase in case this server regains leadership before they join through ++ * the current new leader. They are not yet in 'raft->servers', so not ++ * part of the shared configuration. ++ * + * Also we do not complete commands here, as they can still be completed + * if their log entries have already been replicated to other servers. + * If the entries were actually committed according to the new leader, our + * AppendEntries processing will complete the corresponding commands. + */ + struct raft_server *s; +- HMAP_FOR_EACH (s, hmap_node, &raft->add_servers) { ++ HMAP_FOR_EACH_POP (s, hmap_node, &raft->add_servers) { + raft_send_add_server_reply__(raft, &s->sid, s->address, false, + RAFT_SERVER_LOST_LEADERSHIP); ++ raft_server_destroy(s); + } + if (raft->remove_server) { + raft_send_remove_server_reply__(raft, &raft->remove_server->sid, +@@ -2721,6 +2775,13 @@ raft_send_heartbeats(struct raft *raft) + raft_reset_ping_timer(raft); + } + ++static void ++raft_join_complete(struct raft *raft) ++{ ++ raft->joining = false; ++ raft_update_probe_intervals(raft); ++} ++ + /* Initializes the fields in 's' that represent the leader's view of the + * server. */ + static void +@@ -2758,6 +2819,18 @@ raft_become_leader(struct raft *raft) + raft_reset_election_timer(raft); + raft_reset_ping_timer(raft); + ++ if (raft->joining) { ++ /* It is possible that the server committing this one to the list of ++ * servers lost leadership before the entry is committed but after ++ * it was already replicated to majority of servers. In this case ++ * other servers will recognize this one as a valid cluster member ++ * and may transfer leadership to it and vote for it. This way ++ * we're becoming a cluster leader without receiving reply for a ++ * join request and will commit addition of this server ourselves. */ ++ VLOG_INFO_RL(&rl, "elected as leader while joining"); ++ raft_join_complete(raft); ++ } ++ + struct raft_server *s; + HMAP_FOR_EACH (s, hmap_node, &raft->servers) { + raft_server_init_leader(raft, s); +@@ -2916,12 +2989,12 @@ raft_update_commit_index(struct raft *raft, uint64_t new_commit_index) + } + + while (raft->commit_index < new_commit_index) { ++ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); + uint64_t index = ++raft->commit_index; + const struct raft_entry *e = raft_get_entry(raft, index); + + if (raft_entry_has_data(e)) { + struct raft_command *cmd = raft_find_command_by_eid(raft, &e->eid); +- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); + + if (cmd) { + if (!cmd->index && raft->role == RAFT_LEADER) { +@@ -2965,6 +3038,35 @@ raft_update_commit_index(struct raft *raft, uint64_t new_commit_index) + * reallocate raft->entries, which would invalidate 'e', so + * this case must be last, after the one for 'e->data'. */ + raft_run_reconfigure(raft); ++ } else if (e->servers && !raft_has_uncommitted_configuration(raft)) { ++ struct ovsdb_error *error; ++ struct raft_server *s; ++ struct hmap servers; ++ ++ error = raft_servers_from_json(e->servers, &servers); ++ ovs_assert(!error); ++ HMAP_FOR_EACH (s, hmap_node, &servers) { ++ struct raft_server *server = raft_find_server(raft, &s->sid); ++ ++ if (server && server->phase == RAFT_PHASE_COMMITTING) { ++ /* This server lost leadership while committing ++ * server 's', but it was committed later by a ++ * new leader. */ ++ server->phase = RAFT_PHASE_STABLE; ++ } ++ ++ if (raft->joining && uuid_equals(&s->sid, &raft->sid)) { ++ /* Leadership change happened before previous leader ++ * could commit the change of a servers list, but it ++ * was replicated and a new leader committed it. */ ++ VLOG_INFO_RL(&rl, ++ "added to configuration without reply " ++ "(eid: "UUID_FMT", commit index: %"PRIu64")", ++ UUID_ARGS(&e->eid), index); ++ raft_join_complete(raft); ++ } ++ } ++ raft_servers_destroy(&servers); + } + } + +@@ -3877,6 +3979,10 @@ raft_handle_add_server_request(struct raft *raft, + "to cluster "CID_FMT, s->nickname, SID_ARGS(&s->sid), + rq->address, CID_ARGS(&raft->cid)); + raft_send_append_request(raft, s, 0, "initialize new server"); ++ ++ if (failure_test == FT_TRANSFER_LEADERSHIP_AFTER_STARTING_TO_ADD) { ++ failure_test = FT_TRANSFER_LEADERSHIP; ++ } + } + + static void +@@ -3891,7 +3997,7 @@ raft_handle_add_server_reply(struct raft *raft, + } + + if (rpy->success) { +- raft->joining = false; ++ raft_join_complete(raft); + + /* It is tempting, at this point, to check that this server is part of + * the current configuration. However, this is not necessarily the +@@ -4865,6 +4971,7 @@ raft_get_election_timer_from_log(struct raft *raft) + break; + } + } ++ raft_update_probe_intervals(raft); + } + + static void +@@ -5002,6 +5109,8 @@ raft_unixctl_failure_test(struct unixctl_conn *conn OVS_UNUSED, + } else if (!strcmp(test, + "transfer-leadership-after-sending-append-request")) { + failure_test = FT_TRANSFER_LEADERSHIP_AFTER_SEND_APPEND_REQ; ++ } else if (!strcmp(test, "transfer-leadership-after-starting-to-add")) { ++ failure_test = FT_TRANSFER_LEADERSHIP_AFTER_STARTING_TO_ADD; + } else if (!strcmp(test, "transfer-leadership")) { + failure_test = FT_TRANSFER_LEADERSHIP; + } else if (!strcmp(test, "clear")) { diff --git a/ovsdb/row.h b/ovsdb/row.h index 59f498a20d..6f5e58acb3 100644 --- a/ovsdb/row.h @@ -4539,6 +5649,15 @@ diff --git a/python/build/soutil.py b/python/ovs_build_helpers/soutil.py similarity index 100% rename from python/build/soutil.py rename to python/ovs_build_helpers/soutil.py +diff --git a/rhel/usr_lib_systemd_system_ovsdb-server.service b/rhel/usr_lib_systemd_system_ovsdb-server.service +index 49dc06e38c..558632320c 100644 +--- a/rhel/usr_lib_systemd_system_ovsdb-server.service ++++ b/rhel/usr_lib_systemd_system_ovsdb-server.service +@@ -29,3 +29,4 @@ ExecStop=/usr/share/openvswitch/scripts/ovs-ctl --no-ovs-vswitchd stop + ExecReload=/usr/share/openvswitch/scripts/ovs-ctl --no-ovs-vswitchd \ + ${OVS_USER_OPT} \ + --no-monitor restart $OPTIONS ++TimeoutSec=300 diff --git a/tests/.gitignore b/tests/.gitignore index 83b1cb3b48..3a8c459756 100644 --- a/tests/.gitignore @@ -5066,7 +6185,7 @@ index 14aa554169..6a07e23c64 100644 + AT_CLEANUP diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at -index f242f77f31..c6a7752665 100644 +index f242f77f31..6d0a0172b3 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -547,6 +547,23 @@ ovs-appctl time/warp 1000 100 @@ -5134,7 +6253,65 @@ index f242f77f31..c6a7752665 100644 AT_SETUP([ofproto-dpif - debug_slow action]) OVS_VSWITCHD_START add_of_ports br0 1 2 3 -@@ -7619,12 +7670,14 @@ dummy@ovs-dummy: hit:0 missed:0 +@@ -6144,6 +6195,57 @@ AT_CHECK([test 1 = `$PYTHON3 "$top_srcdir/utilities/ovs-pcap.in" p2-tx.pcap | wc + OVS_VSWITCHD_STOP + AT_CLEANUP + ++AT_SETUP([ofproto-dpif - continuation with meters]) ++AT_KEYWORDS([continuations pause meters]) ++OVS_VSWITCHD_START ++add_of_ports br0 1 2 ++ ++dnl Add meter with id=1. ++AT_CHECK([ovs-ofctl -O OpenFlow13 add-meter br0 'meter=1 pktps bands=type=drop rate=1']) ++ ++AT_DATA([flows.txt], [dnl ++table=0 dl_dst=50:54:00:00:00:0a actions=goto_table(1) ++table=1 dl_dst=50:54:00:00:00:0a actions=controller(pause,meter_id=1) ++]) ++AT_CHECK([ovs-ofctl -O OpenFlow13 add-flows br0 flows.txt]) ++ ++on_exit 'kill $(cat ovs-ofctl.pid)' ++AT_CAPTURE_FILE([ofctl_monitor.log]) ++AT_CHECK([ovs-ofctl monitor br0 65534 invalid_ttl -P nxt_packet_in \ ++ --detach --no-chdir --pidfile 2> ofctl_monitor.log]) ++ ++AT_CHECK([ovs-appctl netdev-dummy/receive p1 \ ++ 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x1234)']) ++ ++OVS_WAIT_UNTIL([test $(wc -l < ofctl_monitor.log) -ge 2]) ++OVS_APP_EXIT_AND_WAIT([ovs-ofctl]) ++AT_CHECK([cat ofctl_monitor.log], [0], [dnl ++NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=14 in_port=1 (via action) data_len=14 (unbuffered) ++vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234 ++]) ++ ++AT_CHECK([ovs-appctl revalidator/purge], [0]) ++AT_CHECK([ovs-ofctl -O OpenFlow13 dump-flows br0 | ofctl_strip | sort], [0], [dnl ++ n_packets=1, n_bytes=14, dl_dst=50:54:00:00:00:0a actions=goto_table:1 ++ table=1, n_packets=1, n_bytes=14, dl_dst=50:54:00:00:00:0a actions=controller(pause,meter_id=1) ++OFPST_FLOW reply (OF1.3): ++]) ++ ++AT_CHECK([ovs-ofctl -O OpenFlow13 dump-meters br0 | ofctl_strip | sort], [0], [dnl ++OFPST_METER_CONFIG reply (OF1.3): ++meter=1 pktps bands= ++type=drop rate=1 ++]) ++ ++AT_CHECK([ovs-ofctl -O OpenFlow13 meter-stats br0 | strip_timers], [0], [dnl ++OFPST_METER reply (OF1.3) (xid=0x2): ++meter:1 flow_count:0 packet_in_count:1 byte_in_count:14 duration:0.0s bands: ++0: packet_count:0 byte_count:0 ++]) ++ ++OVS_VSWITCHD_STOP ++AT_CLEANUP ++ + AT_SETUP([ofproto-dpif - continuation with patch port]) + AT_KEYWORDS([continuations pause resume]) + OVS_VSWITCHD_START( +@@ -7619,12 +7721,14 @@ dummy@ovs-dummy: hit:0 missed:0 vm1 5/3: (dummy: ifindex=2011) ]) @@ -5152,7 +6329,7 @@ index f242f77f31..c6a7752665 100644 dnl Prime ARP Cache for 1.1.2.92 AT_CHECK([ovs-appctl netdev-dummy/receive p0 'recirc_id(0),in_port(1),eth(src=f8:bc:12:44:34:b6,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.92,tip=1.1.2.88,op=2,sha=f8:bc:12:44:34:b6,tha=00:00:00:00:00:00)']) -@@ -7635,10 +7688,13 @@ ovs-vsctl \ +@@ -7635,10 +7739,13 @@ ovs-vsctl \ --id=@sf create sflow targets=\"127.0.0.1:$SFLOW_PORT\" agent=127.0.0.1 \ header=128 sampling=1 polling=0 @@ -5253,6 +6430,123 @@ index 68fb962bd7..dcddb25874 100644 +AT_CHECK([diff -u monitor.log.clear monitor-replay.log.clear]) AT_CLEANUP +diff --git a/tests/ovsdb-cluster.at b/tests/ovsdb-cluster.at +index 9fbf5dc897..987e05103d 100644 +--- a/tests/ovsdb-cluster.at ++++ b/tests/ovsdb-cluster.at +@@ -483,6 +483,112 @@ done + + AT_CLEANUP + ++AT_SETUP([OVSDB cluster - leadership change after replication while joining]) ++AT_KEYWORDS([ovsdb server negative unix cluster join]) ++ ++n=5 ++AT_CHECK([ovsdb-tool '-vPATTERN:console:%c|%p|%m' create-cluster s1.db dnl ++ $abs_srcdir/idltest.ovsschema unix:s1.raft], [0], [], [stderr]) ++cid=$(ovsdb-tool db-cid s1.db) ++schema_name=$(ovsdb-tool schema-name $abs_srcdir/idltest.ovsschema) ++for i in $(seq 2 $n); do ++ AT_CHECK([ovsdb-tool join-cluster s$i.db $schema_name unix:s$i.raft unix:s1.raft]) ++done ++ ++on_exit 'kill $(cat *.pid)' ++on_exit " ++ for i in \$(ls $(pwd)/s[[0-$n]]); do ++ ovs-appctl --timeout 1 -t \$i cluster/status $schema_name; ++ done ++" ++ ++dnl Starting servers one by one asking all exisitng servers to transfer ++dnl leadership after append reply forcing the joining server to try another ++dnl one that will also transfer leadership. Since transfer is happening ++dnl after the servers update is replicated to other servers, one of the ++dnl other servers will actually commit it. It may be a new leader from ++dnl one of the old members or the new joining server itself. ++for i in $(seq $n); do ++ dnl Make sure that all already started servers joined the cluster. ++ for j in $(seq $((i - 1)) ); do ++ AT_CHECK([ovsdb_client_wait unix:s$j.ovsdb $schema_name connected]) ++ done ++ for j in $(seq $((i - 1)) ); do ++ OVS_WAIT_UNTIL([ovs-appctl -t "$(pwd)"/s$j \ ++ cluster/failure-test \ ++ transfer-leadership-after-sending-append-request \ ++ | grep -q "engaged"]) ++ done ++ ++ AT_CHECK([ovsdb-server -v -vconsole:off -vsyslog:off \ ++ --detach --no-chdir --log-file=s$i.log \ ++ --pidfile=s$i.pid --unixctl=s$i \ ++ --remote=punix:s$i.ovsdb s$i.db]) ++done ++ ++dnl Make sure that all servers joined the cluster. ++for i in $(seq $n); do ++ AT_CHECK([ovsdb_client_wait unix:s$i.ovsdb $schema_name connected]) ++done ++ ++for i in $(seq $n); do ++ OVS_APP_EXIT_AND_WAIT_BY_TARGET([$(pwd)/s$i], [s$i.pid]) ++done ++ ++AT_CLEANUP ++ ++AT_SETUP([OVSDB cluster - leadership change before replication while joining]) ++AT_KEYWORDS([ovsdb server negative unix cluster join]) ++ ++n=5 ++AT_CHECK([ovsdb-tool '-vPATTERN:console:%c|%p|%m' create-cluster s1.db dnl ++ $abs_srcdir/idltest.ovsschema unix:s1.raft], [0], [], [stderr]) ++cid=$(ovsdb-tool db-cid s1.db) ++schema_name=$(ovsdb-tool schema-name $abs_srcdir/idltest.ovsschema) ++for i in $(seq 2 $n); do ++ AT_CHECK([ovsdb-tool join-cluster s$i.db $schema_name unix:s$i.raft unix:s1.raft]) ++done ++ ++on_exit 'kill $(cat *.pid)' ++on_exit " ++ for i in \$(ls $(pwd)/s[[0-$n]]); do ++ ovs-appctl --timeout 1 -t \$i cluster/status $schema_name; ++ done ++" ++ ++dnl Starting servers one by one asking all exisitng servers to transfer ++dnl leadership right after starting to add a server. Joining server will ++dnl need to find a new leader that will also transfer leadership. ++dnl This will continue until the same server will not become a leader ++dnl for the second time and will be able to add a new server. ++for i in $(seq $n); do ++ dnl Make sure that all already started servers joined the cluster. ++ for j in $(seq $((i - 1)) ); do ++ AT_CHECK([ovsdb_client_wait unix:s$j.ovsdb $schema_name connected]) ++ done ++ for j in $(seq $((i - 1)) ); do ++ OVS_WAIT_UNTIL([ovs-appctl -t "$(pwd)"/s$j \ ++ cluster/failure-test \ ++ transfer-leadership-after-starting-to-add \ ++ | grep -q "engaged"]) ++ done ++ ++ AT_CHECK([ovsdb-server -v -vconsole:off -vsyslog:off \ ++ --detach --no-chdir --log-file=s$i.log \ ++ --pidfile=s$i.pid --unixctl=s$i \ ++ --remote=punix:s$i.ovsdb s$i.db]) ++done ++ ++dnl Make sure that all servers joined the cluster. ++for i in $(seq $n); do ++ AT_CHECK([ovsdb_client_wait unix:s$i.ovsdb $schema_name connected]) ++done ++ ++for i in $(seq $n); do ++ OVS_APP_EXIT_AND_WAIT_BY_TARGET([$(pwd)/s$i], [s$i.pid]) ++done ++ ++AT_CLEANUP + + + OVS_START_SHELL_HELPERS diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at index df5a9d2fd2..fb568dd823 100644 --- a/tests/ovsdb-idl.at @@ -6267,6 +7561,78 @@ index 7215e36e2d..bc9ed8b740 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) +diff --git a/tests/system-route.at b/tests/system-route.at +index 114aaebc77..c0ecad6cfb 100644 +--- a/tests/system-route.at ++++ b/tests/system-route.at +@@ -64,3 +64,67 @@ Cached: fc00:db8:beef::13/128 dev br0 GW fc00:db8:cafe::1 SRC fc00:db8:cafe::2]) + + OVS_TRAFFIC_VSWITCHD_STOP + AT_CLEANUP ++ ++dnl Checks that OVS doesn't use routes from non-standard tables. ++AT_SETUP([ovs-route - route tables]) ++AT_KEYWORDS([route]) ++OVS_TRAFFIC_VSWITCHD_START() ++ ++dnl Create tap port. ++on_exit 'ip link del p1-route' ++AT_CHECK([ip tuntap add name p1-route mode tap]) ++AT_CHECK([ip link set p1-route up]) ++ ++dnl Add ip address. ++AT_CHECK([ip addr add 10.0.0.17/24 dev p1-route], [0], [stdout]) ++ ++dnl Check that OVS catches route updates. ++OVS_WAIT_UNTIL_EQUAL([ovs-appctl ovs/route/show | grep 'p1-route' | sort], [dnl ++Cached: 10.0.0.0/24 dev p1-route SRC 10.0.0.17 ++Cached: 10.0.0.17/32 dev p1-route SRC 10.0.0.17 local]) ++ ++dnl Add a route to the main routing table and check that OVS caches ++dnl this new route. ++AT_CHECK([ip route add 10.0.0.18/32 dev p1-route]) ++OVS_WAIT_UNTIL_EQUAL([ovs-appctl ovs/route/show | grep 'p1-route' | sort], [dnl ++Cached: 10.0.0.0/24 dev p1-route SRC 10.0.0.17 ++Cached: 10.0.0.17/32 dev p1-route SRC 10.0.0.17 local ++Cached: 10.0.0.18/32 dev p1-route SRC 10.0.0.17]) ++ ++dnl Add a route to a custom routing table and check that OVS doesn't cache it. ++AT_CHECK([ip route add 10.0.0.19/32 dev p1-route table 42]) ++AT_CHECK([ip route show table 42 | grep 'p1-route' | grep -q '10.0.0.19']) ++dnl Give the main thread a chance to act. ++AT_CHECK([ovs-appctl revalidator/wait]) ++dnl Check that OVS didn't learn this route. ++AT_CHECK([ovs-appctl ovs/route/show | grep 'p1-route' | sort], [0], [dnl ++Cached: 10.0.0.0/24 dev p1-route SRC 10.0.0.17 ++Cached: 10.0.0.17/32 dev p1-route SRC 10.0.0.17 local ++Cached: 10.0.0.18/32 dev p1-route SRC 10.0.0.17 ++]) ++ ++dnl Delete a route from the main table and check that OVS removes the route ++dnl from the cache. ++AT_CHECK([ip route del 10.0.0.18/32 dev p1-route]) ++OVS_WAIT_UNTIL_EQUAL([ovs-appctl ovs/route/show | grep 'p1-route' | sort], [dnl ++Cached: 10.0.0.0/24 dev p1-route SRC 10.0.0.17 ++Cached: 10.0.0.17/32 dev p1-route SRC 10.0.0.17 local]) ++ ++dnl Delete a route from a custom routing table and check that the cache ++dnl dosn't change. ++AT_CHECK([ip route del 10.0.0.19/32 dev p1-route table 42]) ++dnl Give the main thread a chance to act. ++AT_CHECK([ovs-appctl revalidator/wait]) ++dnl Check that the cache is still the same. ++AT_CHECK([ovs-appctl ovs/route/show | grep 'p1-route' | sort], [0], [dnl ++Cached: 10.0.0.0/24 dev p1-route SRC 10.0.0.17 ++Cached: 10.0.0.17/32 dev p1-route SRC 10.0.0.17 local ++]) ++ ++dnl Delete ip address. ++AT_CHECK([ip addr del 10.0.0.17/24 dev p1-route], [0], [stdout]) ++dnl Check that routes were removed from OVS. ++OVS_WAIT_UNTIL([test $(ovs-appctl ovs/route/show | grep -c 'p1-route') -eq 0 ]) ++ ++OVS_TRAFFIC_VSWITCHD_STOP ++AT_CLEANUP diff --git a/tests/system-tap.at b/tests/system-tap.at index 871a3bda4f..3d84a53182 100644 --- a/tests/system-tap.at @@ -6281,7 +7647,7 @@ index 871a3bda4f..3d84a53182 100644 ]) diff --git a/tests/system-traffic.at b/tests/system-traffic.at -index 808c492a22..23404a2799 100644 +index 808c492a22..3f6cc80e3f 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -10,13 +10,13 @@ ADD_NAMESPACES(at_ns0, at_ns1) @@ -7138,7 +8504,19 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -2786,7 +2984,7 @@ priority=100,in_port=2,icmp,ct_state=+trk+est,action=1 +@@ -2753,7 +2951,10 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl + icmp,orig=(src=10.1.1.1,dst=10.1.1.2,id=,type=8,code=0),reply=(src=10.1.1.2,dst=10.1.1.1,id=,type=0,code=0) + ]) + +-AT_CHECK([ovs-appctl dpctl/flush-conntrack]) ++AT_CHECK([ovs-appctl dpctl/flush-conntrack 'ct_nw_src=10.1.1.1,ct_nw_dst=10.1.1.2']) ++ ++AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl ++]) + + dnl Pings from ns1->ns0 should fail. + NS_CHECK_EXEC([at_ns1], [ping -q -c 3 -i 0.3 -w 2 10.1.1.1 | FORMAT_PING], [0], [dnl +@@ -2786,7 +2987,7 @@ priority=100,in_port=2,icmp,ct_state=+trk+est,action=1 AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) dnl Pings from ns0->ns1 should work fine. @@ -7147,7 +8525,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -2886,7 +3084,7 @@ NS_CHECK_EXEC([at_ns1], [ping6 -q -c 3 -i 0.3 -w 2 fc00::1 | FORMAT_PING], [0], +@@ -2886,7 +3087,7 @@ NS_CHECK_EXEC([at_ns1], [ping6 -q -c 3 -i 0.3 -w 2 fc00::1 | FORMAT_PING], [0], ]) dnl Pings from ns0->ns1 should work fine. @@ -7156,7 +8534,19 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -3796,7 +3994,7 @@ table=0,in_port=ovs-p1,ct_state=+trk+rel+rpl,icmp,actions=ovs-p0 +@@ -2894,6 +3095,11 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl + icmpv6,orig=(src=fc00::1,dst=fc00::2,id=,type=128,code=0),reply=(src=fc00::2,dst=fc00::1,id=,type=129,code=0) + ]) + ++AT_CHECK([ovs-appctl dpctl/flush-conntrack 'ct_ipv6_src=fc00::1,ct_ipv6_dst=fc00::2']) ++ ++AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl ++]) ++ + OVS_TRAFFIC_VSWITCHD_STOP + AT_CLEANUP + +@@ -3796,7 +4002,7 @@ table=0,in_port=ovs-p1,ct_state=+trk+rel+rpl,icmp,actions=ovs-p0 AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) rm p0.pcap @@ -7165,7 +8555,7 @@ index 808c492a22..23404a2799 100644 OVS_WAIT_UNTIL([grep "listening" tcpdump0_err]) dnl Send UDP packet from 10.1.1.1:1234 to 10.1.1.240:80 -@@ -3837,12 +4035,12 @@ dnl Modify userspace conntrack fragmentation handling. +@@ -3837,12 +4043,12 @@ dnl Modify userspace conntrack fragmentation handling. DPCTL_MODIFY_FRAGMENTATION() dnl Ipv4 fragmentation connectivity check. @@ -7180,7 +8570,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -3914,12 +4112,12 @@ dnl Modify userspace conntrack fragmentation handling. +@@ -3914,12 +4120,12 @@ dnl Modify userspace conntrack fragmentation handling. DPCTL_MODIFY_FRAGMENTATION() dnl Ipv4 fragmentation connectivity check. @@ -7195,7 +8585,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -3960,22 +4158,22 @@ AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) +@@ -3960,22 +4166,22 @@ AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2]) dnl Ipv4 fragmentation connectivity check. @@ -7222,7 +8612,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -4134,12 +4332,12 @@ dnl "connect: Cannot assign requested address" +@@ -4134,12 +4340,12 @@ dnl "connect: Cannot assign requested address" OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2]) dnl Ipv6 fragmentation connectivity check. @@ -7237,7 +8627,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -4216,12 +4414,12 @@ dnl "connect: Cannot assign requested address" +@@ -4216,12 +4422,12 @@ dnl "connect: Cannot assign requested address" OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2]) dnl Ipv4 fragmentation connectivity check. @@ -7252,7 +8642,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -4259,22 +4457,22 @@ AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) +@@ -4259,22 +4465,22 @@ AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00:1::4]) dnl Ipv6 fragmentation connectivity check. @@ -7279,7 +8669,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -4486,18 +4684,18 @@ ADD_NATIVE_TUNNEL([vxlan], [at_vxlan1], [at_ns0], [172.31.1.100], [10.1.1.1/24], +@@ -4486,18 +4692,18 @@ ADD_NATIVE_TUNNEL([vxlan], [at_vxlan1], [at_ns0], [172.31.1.100], [10.1.1.1/24], [id 0 dstport 4789]) dnl First, check the underlay @@ -7302,7 +8692,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -4546,18 +4744,18 @@ dnl "connect: Cannot assign requested address" +@@ -4546,18 +4752,18 @@ dnl "connect: Cannot assign requested address" OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2]) dnl First, check the underlay @@ -7325,7 +8715,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -4670,7 +4868,7 @@ dnl The default udp_single and icmp_first timeouts are 30 seconds in +@@ -4670,7 +4876,7 @@ dnl The default udp_single and icmp_first timeouts are 30 seconds in dnl kernel DP, and 60 seconds in userspace DP. dnl Send ICMP and UDP traffic @@ -7334,7 +8724,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"]) -@@ -4696,7 +4894,7 @@ done +@@ -4696,7 +4902,7 @@ done AT_CHECK([ovs-vsctl --may-exist add-zone-tp $DP_TYPE zone=5 udp_first=1 udp_single=1 icmp_first=1 icmp_reply=1]) dnl Send ICMP and UDP traffic @@ -7343,7 +8733,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"]) -@@ -4714,7 +4912,7 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl +@@ -4714,7 +4920,7 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2)], [0], [dnl ]) dnl Re-send ICMP and UDP traffic to test conntrack cache @@ -7352,7 +8742,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"]) -@@ -4735,7 +4933,7 @@ dnl Set the timeout policy to default again. +@@ -4735,7 +4941,7 @@ dnl Set the timeout policy to default again. AT_CHECK([ovs-vsctl del-zone-tp $DP_TYPE zone=5]) dnl Send ICMP and UDP traffic @@ -7361,7 +8751,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) AT_CHECK([ovs-ofctl -O OpenFlow13 packet-out br0 "in_port=1 packet=50540000000a50540000000908004500001c000000000011a4cd0a0101010a0101020001000200080000 actions=resubmit(,0)"]) -@@ -5001,7 +5199,7 @@ table=2,in_port=1,ip,ct_state=+trk+est,ct_zone=2,action=LOCAL +@@ -5001,7 +5207,7 @@ table=2,in_port=1,ip,ct_state=+trk+est,ct_zone=2,action=LOCAL AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) @@ -7370,7 +8760,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -5072,7 +5270,7 @@ table=4,priority=100,ip,action=output:NXM_NX_REG0[[]] +@@ -5072,7 +5278,7 @@ table=4,priority=100,ip,action=output:NXM_NX_REG0[[]] AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) @@ -7379,7 +8769,55 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -6140,7 +6338,7 @@ table=10 priority=0 action=drop +@@ -5811,11 +6017,11 @@ ADD_NAMESPACES(at_ns0, at_ns1) + ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24") + NS_CHECK_EXEC([at_ns0], [ip link set dev p0 address 80:88:88:88:88:88]) + ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24") ++NS_CHECK_EXEC([at_ns1], [ip link set dev p1 address 80:89:89:89:89:89]) + + dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0. + AT_DATA([flows.txt], [dnl +-in_port=1,tcp,action=ct(commit,zone=1,nat(src=10.1.1.240:34568,random)),2 +-in_port=2,ct_state=-trk,tcp,tp_dst=34567,action=ct(table=0,zone=1,nat) ++in_port=1,tcp,action=ct(commit,zone=1,nat(src=10.1.1.240:34568)),2 + in_port=2,ct_state=-trk,tcp,tp_dst=34568,action=ct(table=0,zone=1,nat) + in_port=2,ct_state=+trk,ct_zone=1,tcp,action=1 + dnl +@@ -5839,17 +6045,29 @@ AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) + + dnl HTTP requests from p0->p1 should work fine. + OVS_START_L7([at_ns1], [http]) +-NS_CHECK_EXEC([at_ns0], [wget 10.1.1.2 -t 1 -T 1 --retry-connrefused -v -o wget0.log]) ++ ++dnl Send a valid SYN to make conntrack pick it up. ++dnl The source port used is 123 to prevent unwanted reuse in the next HTTP request. ++eth=8089898989898088888888880800 ++ip4=4500002800000000400664cc0a0101010a010102 ++tcp=007b005000000000000000005002000099130000 ++syn_pkt=${eth}${ip4}${tcp} ++AT_CHECK([ovs-ofctl packet-out br0 "packet=${syn_pkt} actions=ct(commit,zone=1,nat(src=10.1.1.240:34568))"]) ++ ++AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | uniq], [0], [dnl ++tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=,dport=),reply=(src=10.1.1.2,dst=10.1.1.240,sport=,dport=),zone=1,protoinfo=(state=) ++]) + + NS_CHECK_EXEC([at_ns0], [wget 10.1.1.2 -t 1 -T 1 --retry-connrefused -v -o wget0.log], [4]) + +-AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sed -e 's/dst=10.1.1.2[[45]][[0-9]]/dst=10.1.1.2XX/' | uniq], [0], [dnl +-tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=,dport=),reply=(src=10.1.1.2,dst=10.1.1.2XX,sport=,dport=),zone=1,protoinfo=(state=) ++AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | uniq], [0], [dnl ++tcp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=,dport=),reply=(src=10.1.1.2,dst=10.1.1.240,sport=,dport=),zone=1,protoinfo=(state=) + ]) + + OVS_TRAFFIC_VSWITCHD_STOP(["dnl + /Unable to NAT due to tuple space exhaustion - if DoS attack, use firewalling and\/or zone partitioning./d +-/Dropped .* log messages in last .* seconds \(most recently, .* seconds ago\) due to excessive rate/d"]) ++/Dropped .* log messages in last .* seconds \(most recently, .* seconds ago\) due to excessive rate/d ++/|WARN|.* execute ct.* failed/d"]) + AT_CLEANUP + + AT_SETUP([conntrack - more complex SNAT]) +@@ -6140,7 +6358,7 @@ table=10 priority=0 action=drop AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) rm p0.pcap @@ -7388,7 +8826,7 @@ index 808c492a22..23404a2799 100644 sleep 1 dnl UDP packets from ns0->ns1 should solicit "destination unreachable" response. -@@ -6164,7 +6362,7 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sed -e 's/dst= +@@ -6164,7 +6382,7 @@ AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.1.1.2) | sed -e 's/dst= udp,orig=(src=10.1.1.1,dst=10.1.1.2,sport=,dport=),reply=(src=10.1.1.2,dst=10.1.1.2XX,sport=,dport=),mark=1 ]) @@ -7397,7 +8835,7 @@ index 808c492a22..23404a2799 100644 OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP -@@ -6854,7 +7052,7 @@ dnl waiting, we get occasional failures due to the following error: +@@ -6854,7 +7072,7 @@ dnl waiting, we get occasional failures due to the following error: dnl "connect: Cannot assign requested address" OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::240]) @@ -7406,7 +8844,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -6909,13 +7107,13 @@ OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2]) +@@ -6909,13 +7127,13 @@ OVS_WAIT_UNTIL([ip netns exec at_ns0 ping6 -c 1 fc00::2]) AT_CHECK([ovs-appctl dpctl/flush-conntrack]) rm p0.pcap @@ -7422,7 +8860,7 @@ index 808c492a22..23404a2799 100644 AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fc00::2)], [0], [dnl udp,orig=(src=fc00::1,dst=fc00::2,sport=,dport=),reply=(src=fc00::2,dst=fc00::240,sport=,dport=) -@@ -6944,7 +7142,7 @@ table=0,in_port=ovs-p1,ct_state=+trk+rel+rpl,icmp6,actions=ovs-p0 +@@ -6944,7 +7162,7 @@ table=0,in_port=ovs-p1,ct_state=+trk+rel+rpl,icmp6,actions=ovs-p0 AT_CHECK([ovs-ofctl --bundle add-flows br0 flows.txt]) rm p0.pcap @@ -7431,7 +8869,7 @@ index 808c492a22..23404a2799 100644 OVS_WAIT_UNTIL([grep "listening" tcpdump0_err]) dnl Send UDP packet from [[fc00::1]]:1234 to [[fc00::240]]:80 -@@ -7587,12 +7785,12 @@ ADD_NATIVE_TUNNEL([geneve], [ns_gnv0], [at_ns0], [172.31.1.100], [10.1.1.1/24], +@@ -7587,12 +7805,12 @@ ADD_NATIVE_TUNNEL([geneve], [ns_gnv0], [at_ns0], [172.31.1.100], [10.1.1.1/24], [vni 0]) dnl First, check the underlay @@ -7446,7 +8884,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -7635,7 +7833,7 @@ table=2,in_port=ovs-server,ip,ct_state=+trk+rpl,actions=output:ovs-client +@@ -7635,7 +7853,7 @@ table=2,in_port=ovs-server,ip,ct_state=+trk+rpl,actions=output:ovs-client AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) rm server.pcap @@ -7455,7 +8893,7 @@ index 808c492a22..23404a2799 100644 OVS_WAIT_UNTIL([grep "listening" tcpdump0_err]) dnl Send UDP client->server -@@ -7677,7 +7875,7 @@ dnl Check the ICMP error in reply direction +@@ -7677,7 +7895,7 @@ dnl Check the ICMP error in reply direction AT_CHECK([ovs-appctl dpctl/flush-conntrack zone=42]) rm client.pcap @@ -7464,7 +8902,7 @@ index 808c492a22..23404a2799 100644 OVS_WAIT_UNTIL([grep "listening" tcpdump1_err]) dnl Send UDP client->server -@@ -7715,6 +7913,65 @@ AT_CHECK([ovs-pcap client.pcap | grep 000000002010000000002000], [0], [dnl +@@ -7715,6 +7933,65 @@ AT_CHECK([ovs-pcap client.pcap | grep 000000002010000000002000], [0], [dnl OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP @@ -7530,7 +8968,7 @@ index 808c492a22..23404a2799 100644 AT_BANNER([IGMP]) AT_SETUP([IGMP - flood under normal action]) -@@ -7819,7 +8076,7 @@ dnl CVLAN traffic should match the flow and drop +@@ -7819,7 +8096,7 @@ dnl CVLAN traffic should match the flow and drop AT_CHECK([ovs-appctl revalidator/purge]) AT_CHECK([ovs-vsctl set Open_vSwitch . other_config:vlan-limit=1]) AT_CHECK([ovs-ofctl add-flow br0 "priority=100 dl_type=0x8100 action=drop"]) @@ -7539,7 +8977,7 @@ index 808c492a22..23404a2799 100644 OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP -@@ -7869,11 +8126,11 @@ AT_CHECK([ovs-ofctl --bundle add-flows br2 flows-customer-br.txt]) +@@ -7869,11 +8146,11 @@ AT_CHECK([ovs-ofctl --bundle add-flows br2 flows-customer-br.txt]) OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2]) @@ -7553,7 +8991,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -7925,11 +8182,11 @@ AT_CHECK([ovs-ofctl --bundle add-flows br2 flows-customer-br.txt]) +@@ -7925,11 +8202,11 @@ AT_CHECK([ovs-ofctl --bundle add-flows br2 flows-customer-br.txt]) OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2]) @@ -7567,7 +9005,7 @@ index 808c492a22..23404a2799 100644 3 packets transmitted, 3 received, 0% packet loss, time 0ms ]) -@@ -7977,24 +8234,24 @@ AT_CHECK([ovs-vsctl set port ovs-p2 vlan_mode=dot1q-tunnel tag=4094 cvlans=100,2 +@@ -7977,24 +8254,24 @@ AT_CHECK([ovs-vsctl set port ovs-p2 vlan_mode=dot1q-tunnel tag=4094 cvlans=100,2 OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2]) OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.3.2.2]) @@ -7597,7 +9035,7 @@ index 808c492a22..23404a2799 100644 OVS_TRAFFIC_VSWITCHD_STOP(["/dropping VLAN \(0\|300\) packet received on dot1q-tunnel port/d"]) AT_CLEANUP -@@ -8023,11 +8280,11 @@ AT_CHECK([ovs-ofctl --bundle add-flows br0 flows-br0.txt]) +@@ -8023,11 +8300,11 @@ AT_CHECK([ovs-ofctl --bundle add-flows br0 flows-br0.txt]) OVS_WAIT_UNTIL([ip netns exec at_ns0 ping -c 1 10.2.2.2]) @@ -8343,7 +9781,7 @@ index b1440f5904..97405636f9 100644 +OVS_VSWITCHD_STOP +AT_CLEANUP diff --git a/tests/tunnel.at b/tests/tunnel.at -index ddeb66bc9f..5081a23adc 100644 +index ddeb66bc9f..75072904cc 100644 --- a/tests/tunnel.at +++ b/tests/tunnel.at @@ -333,6 +333,50 @@ set(tunnel(tun_id=0x5,dst=4.4.4.4,ttl=64,flags(df|key))),1 @@ -8413,7 +9851,26 @@ index ddeb66bc9f..5081a23adc 100644 ]) dnl change the flow table to bump the internal table version -@@ -1232,15 +1277,12 @@ OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=dummy \ +@@ -1224,6 +1269,18 @@ OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) + OVS_APP_EXIT_AND_WAIT([ovsdb-server])] + AT_CLEANUP + ++AT_SETUP([tunnel - re-create port with different name]) ++OVS_VSWITCHD_START( ++ [add-port br0 p0 -- set int p0 type=vxlan options:remote_ip=10.10.10.1]) ++ ++AT_CHECK([ovs-vsctl --if-exists del-port p0 -- \ ++ add-port br0 p1 -- \ ++ set int p1 type=vxlan options:remote_ip=10.10.10.1]) ++ ++OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) ++OVS_APP_EXIT_AND_WAIT([ovsdb-server])] ++AT_CLEANUP ++ + AT_SETUP([tunnel - SRV6 basic]) + OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=dummy \ + ofport_request=1 \ +@@ -1232,15 +1289,12 @@ OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=dummy \ ofport_request=2]) OVS_VSWITCHD_DISABLE_TUNNEL_PUSH_POP @@ -8433,6 +9890,18 @@ index ddeb66bc9f..5081a23adc 100644 ]) AT_DATA([flows.txt], [dnl +diff --git a/tests/vlog.at b/tests/vlog.at +index 785014956e..efe91479a6 100644 +--- a/tests/vlog.at ++++ b/tests/vlog.at +@@ -8,6 +8,7 @@ AT_CHECK([$PYTHON3 $srcdir/test-vlog.py --log-file log_file \ + + AT_CHECK([sed -e 's/.*-.*-.*T..:..:..Z |//' \ + -e 's/File ".*", line [[0-9]][[0-9]]*,/File , line ,/' \ ++-e '/\^\+/d' \ + stderr_log], [0], [dnl + 0 | module_0 | EMER | emergency + 1 | module_0 | ERR | error diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 24d0941cf2..25fd38f5f5 100644 --- a/utilities/ovs-ofctl.c diff --git a/SPECS/openvswitch3.2.spec b/SPECS/openvswitch3.2.spec index 85c7a87..539ac60 100644 --- a/SPECS/openvswitch3.2.spec +++ b/SPECS/openvswitch3.2.spec @@ -57,7 +57,7 @@ Summary: Open vSwitch Group: System Environment/Daemons daemon/database/utilities URL: http://www.openvswitch.org/ Version: 3.2.0 -Release: 63%{?dist} +Release: 74%{?dist} # Nearly all of openvswitch is ASL 2.0. The bugtool is LGPLv2+, and the # lib/sflow*.[ch] files are SISSL @@ -761,6 +761,82 @@ exit 0 %endif %changelog +* Mon Apr 29 2024 Open vSwitch CI - 3.2.0-74 +- Merging upstream branch-3.2 [RH git: f695da9bb6] + Commit list: + 4e4463ca55 netdev-dpdk: Fix possible memory leak configuring VF MAC address. + + +* Tue Apr 23 2024 Open vSwitch CI - 3.2.0-73 +- Merging upstream branch-3.2 [RH git: b8c1fee0b4] + Commit list: + f0ccdfc0b3 ovsdb: raft: Fix probe intervals after install snapshot request. + f34dba2f50 ovsdb: raft: Fix inability to join a cluster with a large database. + 8d638257c7 rhel/systemd: Set ovsdb-server timeout to 5 minutes. + + +* Thu Apr 11 2024 Open vSwitch CI - 3.2.0-72 +- Merging upstream branch-3.2 [RH git: b99645bc10] + Commit list: + c88a35fc29 github: Update python to 3.12. + d41d6c16d5 ovsdb-dot: Fix flake8 issues. + c494d7c3f0 ovsdb-doc: Fix syntax warning with Python 3.12 and flake8 issues. + + +* Wed Apr 10 2024 Open vSwitch CI - 3.2.0-71 +- Merging upstream branch-3.2 [RH git: 58bf710200] + Commit list: + bddcf4b123 python: Remove hacking dependency and use recent flake8. + a23eb15ab9 cirrus: Update to FreeBSD 13.3. + + +* Tue Apr 09 2024 Open vSwitch CI - 3.2.0-70 +- Merging upstream branch-3.2 [RH git: 2dd9378db9] + Commit list: + fdc450427c tests: Fix compatibility issue with Python 3.13 in vlog.at. + + +* Fri Apr 05 2024 Open vSwitch CI - 3.2.0-69 +- Merging upstream branch-3.2 [RH git: 32791e9658] + Commit list: + 72ee47fd73 ofproto-dpif-upcall: Fix ukey installation failure logs and counters. + + +* Wed Apr 03 2024 Open vSwitch CI - 3.2.0-68 +- Merging upstream branch-3.2 [RH git: 7d6abcedc9] + Commit list: + 247ad83e57 conntrack: Do not use icmp reverse helper for icmpv6. + 97a3e47d7b conntrack: Fix SNAT with exhaustion system test. + + +* Wed Mar 27 2024 Open vSwitch CI - 3.2.0-67 +- Merging upstream branch-3.2 [RH git: 5943abcb94] + Commit list: + 780b62535f ovsdb: raft: Fix inability to join after leadership change round trip. + 406d24c199 ovsdb: raft: Fix permanent joining state on a cluster member. + cd562af3cc ovsdb: raft: Avoid transferring leadership to unavailable servers. + + +* Wed Mar 27 2024 Open vSwitch CI - 3.2.0-66 +- Merging upstream branch-3.2 [RH git: 2ef6f5cf5b] + Commit list: + 9719f64a34 ofproto-dpif-xlate: Fix continuations with associated metering. + + +* Fri Mar 22 2024 Open vSwitch CI - 3.2.0-65 +- Merging upstream branch-3.2 [RH git: 33d7b0a2ea] + Commit list: + 03d732cc2e ovs-monitor-ipsec: LibreSwan autodetect paths. (#1975039) + dcaae4808f route-table: Avoid routes from non-standard routing tables. + + +* Tue Mar 19 2024 Open vSwitch CI - 3.2.0-64 +- Merging upstream branch-3.2 [RH git: 4999e2c949] + Commit list: + 2ecb466f86 ofproto-dpif: Fix tunnel with different name del/add failure. + f64f9a7cc9 ofpbuf: Prevent undefined behavior in ofpbuf_clone. + + * Tue Mar 12 2024 Open vSwitch CI - 3.2.0-63 - Merging upstream branch-3.2 [RH git: 31cd5f6845] Commit list: