diff --git a/SOURCES/openvswitch-2.17.0.patch b/SOURCES/openvswitch-2.17.0.patch
index 6b336f3..27f0b65 100644
--- a/SOURCES/openvswitch-2.17.0.patch
+++ b/SOURCES/openvswitch-2.17.0.patch
@@ -1,8 +1,8 @@
 diff --git a/.ci/linux-build.sh b/.ci/linux-build.sh
-index 6cd38ff3ef..74872753d0 100755
+index 6cd38ff3ef..f5021e1a8f 100755
 --- a/.ci/linux-build.sh
 +++ b/.ci/linux-build.sh
-@@ -220,7 +220,7 @@ fi
+@@ -220,11 +220,15 @@ fi
  
  if [ "$DPDK" ] || [ "$DPDK_SHARED" ]; then
      if [ -z "$DPDK_VER" ]; then
@@ -11,7 +11,15 @@ index 6cd38ff3ef..74872753d0 100755
      fi
      install_dpdk $DPDK_VER
  fi
-@@ -233,7 +233,7 @@ elif [ "$M32" ]; then
+ 
++if [ "$STD" ]; then
++    CFLAGS_FOR_OVS="${CFLAGS_FOR_OVS} -std=$STD"
++fi
++
+ if [ "$CC" = "clang" ]; then
+     CFLAGS_FOR_OVS="${CFLAGS_FOR_OVS} -Wno-error=unused-command-line-argument"
+ elif [ "$M32" ]; then
+@@ -233,7 +237,7 @@ elif [ "$M32" ]; then
      # difference on 'configure' and 'make' stages.
      export CC="$CC -m32"
  elif [ "$TRAVIS_ARCH" != "aarch64" ]; then
@@ -20,7 +28,7 @@ index 6cd38ff3ef..74872753d0 100755
      if [ "$AFXDP" ]; then
          # netdev-afxdp uses memset for 64M for umem initialization.
          SPARSE_FLAGS="${SPARSE_FLAGS} -Wno-memcpy-max-count"
-@@ -244,9 +244,7 @@ fi
+@@ -244,9 +248,7 @@ fi
  if [ "$ASAN" ]; then
      # This will override default option configured in tests/atlocal.in.
      export ASAN_OPTIONS='detect_leaks=1'
@@ -73,7 +81,7 @@ index a7ae793bc4..c460103bb1 100644
      memory: 4G
  
 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
-index eac3504e48..6ccab8e908 100644
+index eac3504e48..c923df3ea7 100644
 --- a/.github/workflows/build-and-test.yml
 +++ b/.github/workflows/build-and-test.yml
 @@ -6,7 +6,7 @@ jobs:
@@ -85,7 +93,11 @@ index eac3504e48..6ccab8e908 100644
          libssl-dev llvm-dev libelf-dev libnuma-dev libpcap-dev  \
          ninja-build selinux-policy-dev
        deb_dependencies: |
-@@ -25,7 +25,7 @@ jobs:
+@@ -22,10 +22,11 @@ jobs:
+       LIBS:        ${{ matrix.libs }}
+       M32:         ${{ matrix.m32 }}
+       OPTS:        ${{ matrix.opts }}
++      STD:         ${{ matrix.std }}
        TESTSUITE:   ${{ matrix.testsuite }}
  
      name: linux ${{ join(matrix.*, ' ') }}
@@ -94,7 +106,19 @@ index eac3504e48..6ccab8e908 100644
      timeout-minutes: 30
  
      strategy:
-@@ -111,7 +111,7 @@ jobs:
+@@ -37,6 +38,11 @@ jobs:
+           - compiler:     clang
+             opts:         --disable-ssl
+ 
++          - compiler:     gcc
++            std:          c99
++          - compiler:     clang
++            std:          c99
++
+           - compiler:     gcc
+             testsuite:    test
+             kernel:       3.16
+@@ -111,7 +117,7 @@ jobs:
  
      steps:
      - name: checkout
@@ -103,7 +127,7 @@ index eac3504e48..6ccab8e908 100644
  
      - name: update PATH
        run:  |
-@@ -119,7 +119,7 @@ jobs:
+@@ -119,7 +125,7 @@ jobs:
          echo "$HOME/.local/bin" >> $GITHUB_PATH
  
      - name: set up python
@@ -112,7 +136,7 @@ index eac3504e48..6ccab8e908 100644
        with:
          python-version: '3.9'
  
-@@ -135,7 +135,7 @@ jobs:
+@@ -135,7 +141,7 @@ jobs:
  
      - name: cache
        if:   matrix.dpdk != '' || matrix.dpdk_shared != ''
@@ -121,7 +145,7 @@ index eac3504e48..6ccab8e908 100644
        env:
          matrix_key: ${{ matrix.dpdk }}${{ matrix.dpdk_shared }}
          ci_key:     ${{ hashFiles('dpdk-ci-signature') }}
-@@ -163,7 +163,7 @@ jobs:
+@@ -163,7 +169,7 @@ jobs:
  
      - name: upload deb packages
        if:   matrix.deb_package != ''
@@ -130,7 +154,7 @@ index eac3504e48..6ccab8e908 100644
        with:
          name: deb-packages
          path: '/home/runner/work/ovs/*.deb'
-@@ -182,7 +182,7 @@ jobs:
+@@ -182,7 +188,7 @@ jobs:
  
      - name: upload logs on failure
        if: failure() || cancelled()
@@ -139,7 +163,7 @@ index eac3504e48..6ccab8e908 100644
        with:
          name: logs-linux-${{ join(matrix.*, '-') }}
          path: logs.tgz
-@@ -201,13 +201,13 @@ jobs:
+@@ -201,13 +207,13 @@ jobs:
  
      steps:
      - name: checkout
@@ -155,7 +179,7 @@ index eac3504e48..6ccab8e908 100644
        with:
          python-version: '3.9'
      - name: install dependencies
-@@ -218,7 +218,7 @@ jobs:
+@@ -218,7 +224,7 @@ jobs:
        run:  ./.ci/osx-build.sh
      - name: upload logs on failure
        if: failure()
@@ -247,10 +271,33 @@ index c4300cd53e..a297aadac8 100644
  
  - GNU make.
 diff --git a/Documentation/ref/ovs-actions.7.rst b/Documentation/ref/ovs-actions.7.rst
-index b59b7634fa..d138956556 100644
+index b59b7634fa..36adcc5db2 100644
 --- a/Documentation/ref/ovs-actions.7.rst
 +++ b/Documentation/ref/ovs-actions.7.rst
-@@ -1380,7 +1380,7 @@ The ``delete_field`` action
+@@ -694,7 +694,8 @@ encapsulated in an OpenFlow ``packet-in`` message.  The supported options are:
+     Limit to *max_len* the number of bytes of the packet to send in the
+     ``packet-in.``  A *max_len* of 0 prevents any of the packet from being
+     sent (thus, only metadata is included).  By default, the entire packet is
+-    sent, equivalent to a *max_len* of 65535.
++    sent, equivalent to a *max_len* of 65535.  This option has no effect in
++    Open vSwith 2.7 and later: the entire packet will always be sent.
+ 
+   ``reason=``\ *reason*
+     Specify *reason* as the reason for sending the message in the
+@@ -733,6 +734,12 @@ encapsulated in an OpenFlow ``packet-in`` message.  The supported options are:
+   options require the Open vSwitch ``NXAST_CONTROLLER`` extension action added
+   in Open vSwitch 1.6.
+ 
++  Open vSwitch 2.7 and later is configured to not buffer packets for the
++  packet-in event.  As a result, the full packet is always sent to
++  controllers.  This means that the ``max_len`` option has no effect on the
++  ``controller`` action, and all values (even 0) are equivalent to the default
++  value of 65535.
++
+ 
+ The ``enqueue`` action
+ ----------------------
+@@ -1380,7 +1387,7 @@ The ``delete_field`` action
    | ``delete_field:``\ *field*
  
  The ``delete_field`` action deletes a *field* in the syntax described under
@@ -348,6 +395,28 @@ index 27be4aa412..1dc406170f 100644
 +   <Documentation/internals/committer-grant-revocation.rst>`__
 +.. |emeritus-status|  replace:: `Emeritus Status for OVS Committers
 +   <Documentation/internals/committer-emeritus-status.rst>`__
+diff --git a/Makefile.am b/Makefile.am
+index cb8076433e..22227c4957 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -368,7 +368,7 @@ ALL_LOCAL += manpage-check
+ manpage-check: $(man_MANS) $(dist_man_MANS) $(noinst_man_MANS)
+ 	@error=false; \
+ 	for manpage in $?; do \
+-	  LANG=en_US.UTF-8 groff -w mac -w delim -w escape -w input -w missing -w tab -T utf8 -man -p -z $$manpage >$@.tmp 2>&1; \
++	  LANG=en_US.UTF-8 groff -t -w mac -w delim -w escape -w input -w missing -w tab -T utf8 -man -p -z $$manpage >$@.tmp 2>&1; \
+ 	  if grep warning: $@.tmp; then error=:; fi; \
+ 	  rm -f $@.tmp; \
+ 	done; \
+@@ -414,7 +414,7 @@ endif
+ CLEANFILES += flake8-check
+ 
+ -include manpages.mk
+-manpages.mk: $(MAN_ROOTS) build-aux/sodepends.py python/build/soutil.py
++manpages.mk: $(MAN_ROOTS) build-aux/sodepends.py python/ovs_build_helpers/soutil.py
+ 	@PYTHONPATH=$$PYTHONPATH$(psep)$(srcdir)/python $(PYTHON3) $(srcdir)/build-aux/sodepends.py -I. -I$(srcdir) $(MAN_ROOTS) >$(@F).tmp
+ 	@if cmp -s $(@F).tmp $@; then \
+ 	  touch $@; \
 diff --git a/NEWS b/NEWS
 index c10e9bfacc..673f227202 100644
 --- a/NEWS
@@ -531,6 +600,74 @@ index 0c360fd1ef..c981f90bc7 100644
       [], [enable_sparse=no])
     AM_CONDITIONAL([ENABLE_SPARSE_BY_DEFAULT], [test $enable_sparse = yes])])
  
+diff --git a/build-aux/extract-ofp-fields b/build-aux/extract-ofp-fields
+index 8766995d9a..9fb4df98ad 100755
+--- a/build-aux/extract-ofp-fields
++++ b/build-aux/extract-ofp-fields
+@@ -5,7 +5,8 @@ import sys
+ import os.path
+ import re
+ import xml.dom.minidom
+-import build.nroff
++
++from ovs_build_helpers import nroff
+ 
+ line = ""
+ 
+@@ -578,7 +579,7 @@ def field_to_xml(field_node, f, body, summary):
+     body += [""".PP
+ \\fB%s Field\\fR
+ .TS
+-tab(;);
++tab(;),nowarn;
+ l lx.
+ """ % title]
+ 
+@@ -636,7 +637,7 @@ l lx.
+     body += [".TE\n"]
+ 
+     body += ['.PP\n']
+-    body += [build.nroff.block_xml_to_nroff(field_node.childNodes)]
++    body += [nroff.block_xml_to_nroff(field_node.childNodes)]
+ 
+ def group_xml_to_nroff(group_node, fields):
+     title = group_node.attributes['title'].nodeValue
+@@ -648,14 +649,14 @@ def group_xml_to_nroff(group_node, fields):
+             id_ = node.attributes['id'].nodeValue
+             field_to_xml(node, fields[id_], body, summary)
+         else:
+-            body += [build.nroff.block_xml_to_nroff([node])]
++            body += [nroff.block_xml_to_nroff([node])]
+ 
+     content = [
+         '.bp\n',
+-        '.SH \"%s\"\n' % build.nroff.text_to_nroff(title.upper() + " FIELDS"),
++        '.SH \"%s\"\n' % nroff.text_to_nroff(title.upper() + " FIELDS"),
+         '.SS "Summary:"\n',
+         '.TS\n',
+-        'tab(;);\n',
++        'tab(;),nowarn;\n',
+         'l l l l l l l.\n',
+         'Name;Bytes;Mask;RW?;Prereqs;NXM/OXM Support\n',
+         '\_;\_;\_;\_;\_;\_\n']
+@@ -665,7 +666,7 @@ def group_xml_to_nroff(group_node, fields):
+     return ''.join(content)
+ 
+ def make_oxm_classes_xml(document):
+-    s = '''tab(;);
++    s = '''tab(;),nowarn;
+ l l l.
+ Prefix;Vendor;Class
+ \_;\_;\_
+@@ -753,7 +754,7 @@ ovs\-fields \- protocol header fields in OpenFlow and Open vSwitch
+         elif node.nodeType == node.COMMENT_NODE:
+             pass
+         else:
+-            s += build.nroff.block_xml_to_nroff([node])
++            s += nroff.block_xml_to_nroff([node])
+ 
+     for f in fields:
+         if "used" not in f:
 diff --git a/build-aux/generate-dhparams-c b/build-aux/generate-dhparams-c
 index 1884c99e1f..aca1dbca91 100755
 --- a/build-aux/generate-dhparams-c
@@ -633,6 +770,74 @@ index 1884c99e1f..aca1dbca91 100755
 +dhparam_to_c lib/dh2048.pem
 +dhparam_to_c lib/dh4096.pem
 +echo "#endif"
+diff --git a/build-aux/sodepends.py b/build-aux/sodepends.py
+index 45812bcbd7..ac8dd61a4b 100755
+--- a/build-aux/sodepends.py
++++ b/build-aux/sodepends.py
+@@ -14,9 +14,10 @@
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ 
+-from build import soutil
+ import sys
+ 
++from ovs_build_helpers import soutil
++
+ 
+ def sodepends(include_dirs, filenames, dst):
+     ok = True
+diff --git a/build-aux/soexpand.py b/build-aux/soexpand.py
+index 00adcf47a3..7d4dc0486a 100755
+--- a/build-aux/soexpand.py
++++ b/build-aux/soexpand.py
+@@ -14,9 +14,10 @@
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ 
+-from build import soutil
+ import sys
+ 
++from ovs_build_helpers import soutil
++
+ 
+ def soexpand(include_dirs, src, dst):
+     ok = True
+diff --git a/build-aux/xml2nroff b/build-aux/xml2nroff
+index ee5553f456..3e937910be 100755
+--- a/build-aux/xml2nroff
++++ b/build-aux/xml2nroff
+@@ -18,7 +18,7 @@ import getopt
+ import sys
+ import xml.dom.minidom
+ 
+-import build.nroff
++from ovs_build_helpers import nroff
+ 
+ argv0 = sys.argv[0]
+ 
+@@ -90,10 +90,10 @@ def manpage_to_nroff(xml_file, subst, include_path, version=None):
+ .  I "\\$1"
+ .  RE
+ ..
+-''' % (build.nroff.text_to_nroff(program), build.nroff.text_to_nroff(section),
+-       build.nroff.text_to_nroff(title), build.nroff.text_to_nroff(version))
++''' % (nroff.text_to_nroff(program), nroff.text_to_nroff(section),
++       nroff.text_to_nroff(title), nroff.text_to_nroff(version))
+ 
+-    s += build.nroff.block_xml_to_nroff(doc.childNodes) + "\n"
++    s += nroff.block_xml_to_nroff(doc.childNodes) + "\n"
+ 
+     return s
+ 
+@@ -139,7 +139,7 @@ if __name__ == "__main__":
+ 
+     try:
+         s = manpage_to_nroff(args[0], subst, include_path, version)
+-    except build.nroff.error.Error as e:
++    except nroff.error.Error as e:
+         sys.stderr.write("%s: %s\n" % (argv0, e.msg))
+         sys.exit(1)
+     for line in s.splitlines():
 diff --git a/configure.ac b/configure.ac
 index 4e9bcce272..134106f54a 100644
 --- a/configure.ac
@@ -50266,6 +50471,27 @@ index 0000000000..6fae6f727c
 +
 +#endif /* __KERNEL__ || !HAVE_TCA_STATS_PKT64 */
 +#endif /* __LINUX_GEN_STATS_WRAPPER_H */
+diff --git a/include/openvswitch/compiler.h b/include/openvswitch/compiler.h
+index cf009f8264..52614a5ac0 100644
+--- a/include/openvswitch/compiler.h
++++ b/include/openvswitch/compiler.h
+@@ -37,6 +37,16 @@
+ #define OVS_NO_RETURN
+ #endif
+ 
++#ifndef typeof
++#define typeof __typeof__
++#endif
++
++#ifndef __cplusplus
++#ifndef asm
++#define asm __asm__
++#endif
++#endif
++
+ #if __GNUC__ && !__CHECKER__
+ #define OVS_UNUSED __attribute__((__unused__))
+ #define OVS_PRINTF_FORMAT(FMT, ARG1) __attribute__((__format__(printf, FMT, ARG1)))
 diff --git a/include/openvswitch/dynamic-string.h b/include/openvswitch/dynamic-string.h
 index ee18217107..1c262b0494 100644
 --- a/include/openvswitch/dynamic-string.h
@@ -50939,7 +51165,7 @@ index a8b0705d9f..631a8fca80 100755
          """Remove all OVS IPsec related state from the NSS database"""
          try:
 diff --git a/lib/automake.mk b/lib/automake.mk
-index a23cdc4ade..e9a5978e88 100644
+index a23cdc4ade..3c4a58ed9c 100644
 --- a/lib/automake.mk
 +++ b/lib/automake.mk
 @@ -38,8 +38,6 @@ lib_libopenvswitchavx512_la_CFLAGS = \
@@ -50960,6 +51186,15 @@ index a23cdc4ade..e9a5978e88 100644
  	lib/crc32c.c \
  	lib/crc32c.h \
  	lib/csum.c \
+@@ -437,7 +437,7 @@ lib_libsflow_la_SOURCES = \
+ 	lib/sflow_poller.c \
+ 	lib/sflow_receiver.c
+ lib_libsflow_la_CPPFLAGS = $(AM_CPPFLAGS)
+-lib_libsflow_la_CFLAGS = $(AM_CFLAGS)
++lib_libsflow_la_CFLAGS = $(AM_CFLAGS) -D_BSD_SOURCE -D_DEFAULT_SOURCE
+ if HAVE_WNO_UNUSED
+ lib_libsflow_la_CFLAGS += -Wno-unused
+ endif
 diff --git a/lib/cfm.c b/lib/cfm.c
 index cc43e70e31..c3742f3de2 100644
 --- a/lib/cfm.c
@@ -52198,7 +52433,7 @@ index 66016eb099..7425dd44e7 100644
      /* Statistics. */
      struct dp_netdev_flow_stats stats;
 diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
-index 9f35713ef5..5b0047f5c7 100644
+index 9f35713ef5..f1895aae36 100644
 --- a/lib/dpif-netdev.c
 +++ b/lib/dpif-netdev.c
 @@ -93,7 +93,8 @@ VLOG_DEFINE_THIS_MODULE(dpif_netdev);
@@ -52253,7 +52488,7 @@ index 9f35713ef5..5b0047f5c7 100644
  
      item->timestamp = pmd->ctx.now;
      dp_netdev_offload_flow_enqueue(item);
-@@ -3335,6 +3335,28 @@ netdev_flow_key_init_masked(struct netdev_flow_key *dst,
+@@ -3335,6 +3335,27 @@ netdev_flow_key_init_masked(struct netdev_flow_key *dst,
                              (dst_u64 - miniflow_get_values(&dst->mf)) * 8);
  }
  
@@ -52262,14 +52497,13 @@ index 9f35713ef5..5b0047f5c7 100644
 +netdev_flow_key_init(struct netdev_flow_key *key,
 +                     const struct flow *flow)
 +{
-+    uint64_t *dst = miniflow_values(&key->mf);
 +    uint32_t hash = 0;
 +    uint64_t value;
 +
 +    miniflow_map_init(&key->mf, flow);
 +    miniflow_init(&key->mf, flow);
 +
-+    size_t n = dst - miniflow_get_values(&key->mf);
++    size_t n = miniflow_n_values(&key->mf);
 +
 +    FLOW_FOR_EACH_IN_MAPS (value, flow, key->mf.map) {
 +        hash = hash_add64(hash, value);
@@ -52282,7 +52516,7 @@ index 9f35713ef5..5b0047f5c7 100644
  static inline void
  emc_change_entry(struct emc_entry *ce, struct dp_netdev_flow *flow,
                   const struct netdev_flow_key *key)
-@@ -4095,6 +4117,7 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd,
+@@ -4095,6 +4116,7 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd,
      flow->dead = false;
      flow->batch = NULL;
      flow->mark = INVALID_FLOW_MARK;
@@ -52290,7 +52524,7 @@ index 9f35713ef5..5b0047f5c7 100644
      *CONST_CAST(unsigned *, &flow->pmd_id) = pmd->core_id;
      *CONST_CAST(struct flow *, &flow->flow) = match->flow;
      *CONST_CAST(ovs_u128 *, &flow->ufid) = *ufid;
-@@ -4129,7 +4152,7 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd,
+@@ -4129,7 +4151,7 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd,
      }
  
      queue_netdev_flow_put(pmd, flow, match, actions, actions_len,
@@ -52299,7 +52533,7 @@ index 9f35713ef5..5b0047f5c7 100644
      log_netdev_flow_change(flow, match, NULL, actions, actions_len);
  
      return flow;
-@@ -4143,7 +4166,7 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd,
+@@ -4143,7 +4165,7 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd,
                  const struct dpif_flow_put *put,
                  struct dpif_flow_stats *stats)
  {
@@ -52308,7 +52542,7 @@ index 9f35713ef5..5b0047f5c7 100644
      int error = 0;
  
      if (stats) {
-@@ -4151,16 +4174,35 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd,
+@@ -4151,16 +4173,35 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd,
      }
  
      ovs_mutex_lock(&pmd->flow_mutex);
@@ -52352,7 +52586,7 @@ index 9f35713ef5..5b0047f5c7 100644
              struct dp_netdev_actions *new_actions;
              struct dp_netdev_actions *old_actions;
  
-@@ -4171,7 +4213,7 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd,
+@@ -4171,7 +4212,7 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd,
              ovsrcu_set(&netdev_flow->actions, new_actions);
  
              queue_netdev_flow_put(pmd, netdev_flow, match,
@@ -52361,7 +52595,7 @@ index 9f35713ef5..5b0047f5c7 100644
                                    DP_NETDEV_FLOW_OFFLOAD_OP_MOD);
              log_netdev_flow_change(netdev_flow, match, old_actions,
                                     put->actions, put->actions_len);
-@@ -4191,15 +4233,11 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd,
+@@ -4191,15 +4232,11 @@ flow_put_on_pmd(struct dp_netdev_pmd_thread *pmd,
                   *   counter, and subtracting it before outputting the stats */
                  error = EOPNOTSUPP;
              }
@@ -52379,7 +52613,7 @@ index 9f35713ef5..5b0047f5c7 100644
      ovs_mutex_unlock(&pmd->flow_mutex);
      return error;
  }
-@@ -4208,7 +4246,7 @@ static int
+@@ -4208,7 +4245,7 @@ static int
  dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
  {
      struct dp_netdev *dp = get_dp_netdev(dpif);
@@ -52388,7 +52622,7 @@ index 9f35713ef5..5b0047f5c7 100644
      struct dp_netdev_pmd_thread *pmd;
      struct match match;
      ovs_u128 ufid;
-@@ -4257,9 +4295,12 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
+@@ -4257,9 +4294,12 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
  
      /* Must produce a netdev_flow_key for lookup.
       * Use the same method as employed to create the key when adding
@@ -52404,7 +52638,7 @@ index 9f35713ef5..5b0047f5c7 100644
  
      if (put->pmd_id == PMD_ID_NULL) {
          if (cmap_count(&dp->poll_threads) == 0) {
-@@ -4778,8 +4819,8 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config)
+@@ -4778,8 +4818,8 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config)
      uint32_t insert_min, cur_min;
      uint32_t tx_flush_interval, cur_tx_flush_interval;
      uint64_t rebalance_intvl;
@@ -52415,7 +52649,7 @@ index 9f35713ef5..5b0047f5c7 100644
      bool log_autolb = false;
      enum sched_assignment_type pmd_rxq_assign_type;
  
-@@ -4880,8 +4921,12 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config)
+@@ -4880,8 +4920,12 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config)
  
      struct pmd_auto_lb *pmd_alb = &dp->pmd_alb;
  
@@ -52430,7 +52664,7 @@ index 9f35713ef5..5b0047f5c7 100644
  
      /* Input is in min, convert it to msec. */
      rebalance_intvl =
-@@ -4894,21 +4939,21 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config)
+@@ -4894,21 +4938,21 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config)
          log_autolb = true;
      }
  
@@ -52458,7 +52692,7 @@ index 9f35713ef5..5b0047f5c7 100644
      if (rebalance_load > 100) {
          rebalance_load = ALB_LOAD_THRESHOLD;
      }
-@@ -4916,7 +4961,7 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config)
+@@ -4916,7 +4960,7 @@ dpif_netdev_set_config(struct dpif *dpif, const struct smap *other_config)
      if (rebalance_load != cur_rebalance_load) {
          atomic_store_relaxed(&pmd_alb->rebalance_load_thresh,
                               rebalance_load);
@@ -52467,7 +52701,7 @@ index 9f35713ef5..5b0047f5c7 100644
                    rebalance_load);
          log_autolb = true;
      }
-@@ -5425,7 +5470,6 @@ port_reconfigure(struct dp_netdev_port *port)
+@@ -5425,7 +5469,6 @@ port_reconfigure(struct dp_netdev_port *port)
  
          port->rxqs[i].port = port;
          port->rxqs[i].is_vhost = !strncmp(port->type, "dpdkvhost", 9);
@@ -52475,7 +52709,7 @@ index 9f35713ef5..5b0047f5c7 100644
  
          err = netdev_rxq_open(netdev, &port->rxqs[i].rx, i);
          if (err) {
-@@ -5684,23 +5728,28 @@ sched_numa_list_put_in_place(struct sched_numa_list *numa_list)
+@@ -5684,23 +5727,28 @@ sched_numa_list_put_in_place(struct sched_numa_list *numa_list)
      }
  }
  
@@ -52509,7 +52743,7 @@ index 9f35713ef5..5b0047f5c7 100644
                      rxq->pmd->numa_id !=
                          netdev_get_numa_id(rxq->port->netdev)) {
                      return true;
-@@ -6000,10 +6049,10 @@ sched_numa_list_schedule(struct sched_numa_list *numa_list,
+@@ -6000,10 +6048,10 @@ sched_numa_list_schedule(struct sched_numa_list *numa_list,
              /* Find any numa with available PMDs. */
              for (int j = 0; j < n_numa; j++) {
                  numa = sched_numa_list_next(numa_list, last_cross_numa);
@@ -52521,7 +52755,7 @@ index 9f35713ef5..5b0047f5c7 100644
                  numa = NULL;
              }
          }
-@@ -6111,7 +6160,7 @@ sched_numa_list_variance(struct sched_numa_list *numa_list)
+@@ -6111,7 +6159,7 @@ sched_numa_list_variance(struct sched_numa_list *numa_list)
   * pmd_rebalance_dry_run() can be avoided when it is not needed.
   */
  static bool
@@ -52530,7 +52764,7 @@ index 9f35713ef5..5b0047f5c7 100644
      OVS_REQ_RDLOCK(dp->port_rwlock)
  {
      struct dp_netdev_pmd_thread *pmd;
-@@ -6342,11 +6391,11 @@ pmd_remove_stale_ports(struct dp_netdev *dp,
+@@ -6342,11 +6390,11 @@ pmd_remove_stale_ports(struct dp_netdev *dp,
      OVS_EXCLUDED(pmd->port_mutex)
      OVS_REQ_RDLOCK(dp->port_rwlock)
  {
@@ -52545,7 +52779,7 @@ index 9f35713ef5..5b0047f5c7 100644
          struct dp_netdev_port *port = poll->rxq->port;
  
          if (port->need_reconfigure
-@@ -6354,7 +6403,7 @@ pmd_remove_stale_ports(struct dp_netdev *dp,
+@@ -6354,7 +6402,7 @@ pmd_remove_stale_ports(struct dp_netdev *dp,
              dp_netdev_del_rxq_from_pmd(pmd, poll);
          }
      }
@@ -52554,7 +52788,7 @@ index 9f35713ef5..5b0047f5c7 100644
          struct dp_netdev_port *port = tx->port;
  
          if (port->need_reconfigure
-@@ -6430,8 +6479,7 @@ reconfigure_datapath(struct dp_netdev *dp)
+@@ -6430,8 +6478,7 @@ reconfigure_datapath(struct dp_netdev *dp)
      /* We only reconfigure the ports that we determined above, because they're
       * not being used by any pmd thread at the moment.  If a port fails to
       * reconfigure we remove it from the datapath. */
@@ -52564,7 +52798,7 @@ index 9f35713ef5..5b0047f5c7 100644
          int err;
  
          if (!port->need_reconfigure) {
-@@ -6487,10 +6535,10 @@ reconfigure_datapath(struct dp_netdev *dp)
+@@ -6487,10 +6534,10 @@ reconfigure_datapath(struct dp_netdev *dp)
      }
  
      CMAP_FOR_EACH (pmd, node, &dp->poll_threads) {
@@ -52577,7 +52811,7 @@ index 9f35713ef5..5b0047f5c7 100644
              if (poll->rxq->pmd != pmd) {
                  dp_netdev_del_rxq_from_pmd(pmd, poll);
  
-@@ -6682,7 +6730,7 @@ dpif_netdev_run(struct dpif *dpif)
+@@ -6682,7 +6729,7 @@ dpif_netdev_run(struct dpif *dpif)
              if (pmd_rebalance &&
                  !dp_netdev_is_reconf_required(dp) &&
                  !ports_require_restart(dp) &&
@@ -52586,7 +52820,7 @@ index 9f35713ef5..5b0047f5c7 100644
                  pmd_rebalance_dry_run(dp)) {
                  VLOG_INFO("PMD auto load balance dry run. "
                            "Requesting datapath reconfigure.");
-@@ -7364,15 +7412,15 @@ static struct dp_netdev_pmd_thread *
+@@ -7364,15 +7411,15 @@ static struct dp_netdev_pmd_thread *
  dp_netdev_get_pmd(struct dp_netdev *dp, unsigned core_id)
  {
      struct dp_netdev_pmd_thread *pmd;
@@ -52608,7 +52842,7 @@ index 9f35713ef5..5b0047f5c7 100644
  }
  
  /* Sets the 'struct dp_netdev_pmd_thread' for non-pmd threads. */
-@@ -7505,6 +7553,7 @@ dp_netdev_destroy_pmd(struct dp_netdev_pmd_thread *pmd)
+@@ -7505,6 +7552,7 @@ dp_netdev_destroy_pmd(struct dp_netdev_pmd_thread *pmd)
      seq_destroy(pmd->reload_seq);
      ovs_mutex_destroy(&pmd->port_mutex);
      ovs_mutex_destroy(&pmd->bond_mutex);
@@ -52616,7 +52850,7 @@ index 9f35713ef5..5b0047f5c7 100644
      free(pmd);
  }
  
-@@ -8020,17 +8069,15 @@ dp_netdev_hw_flow(const struct dp_netdev_pmd_thread *pmd,
+@@ -8020,17 +8068,15 @@ dp_netdev_hw_flow(const struct dp_netdev_pmd_thread *pmd,
  #ifdef ALLOW_EXPERIMENTAL_API /* Packet restoration API required. */
      /* Restore the packet if HW processing was terminated before completion. */
      struct dp_netdev_rxq *rxq = pmd->ctx.last_rxq;
@@ -52641,7 +52875,7 @@ index 9f35713ef5..5b0047f5c7 100644
          }
      }
  #endif
-@@ -9495,6 +9542,7 @@ dpif_netdev_bond_stats_get(struct dpif *dpif, uint32_t bond_id,
+@@ -9495,6 +9541,7 @@ dpif_netdev_bond_stats_get(struct dpif *dpif, uint32_t bond_id,
  const struct dpif_class dpif_netdev_class = {
      "netdev",
      true,                       /* cleanup_required */
@@ -53901,10 +54135,49 @@ index e03cd8d0c5..474344194f 100644
 +    }
 +}
 diff --git a/lib/meta-flow.xml b/lib/meta-flow.xml
-index 28865f88c8..ff81fddc5e 100644
+index 28865f88c8..67788baf25 100644
 --- a/lib/meta-flow.xml
 +++ b/lib/meta-flow.xml
-@@ -4303,9 +4303,9 @@ r r c c c.
+@@ -3517,23 +3517,24 @@ actions=clone(load:0->NXM_OF_IN_PORT[],output:123)
+     </p>
+ 
+     <tbl>
++tab(;);
+ r r r r r.
+-Criteria        OpenFlow 1.0    OpenFlow 1.1    OpenFlow 1.2+   NXM
+-\_      \_      \_      \_      \_
+-[1]     \fL????\fR/\fL1\fR,\fL??\fR/\fL?\fR     \fL????\fR/\fL1\fR,\fL??\fR/\fL?\fR     \fL0000\fR/\fL0000\fR,\fL--\fR  \fL0000\fR/\fL0000\fR
+-[2]     \fLffff\fR/\fL0\fR,\fL??\fR/\fL?\fR     \fLffff\fR/\fL0\fR,\fL??\fR/\fL?\fR     \fL0000\fR/\fLffff\fR,\fL--\fR  \fL0000\fR/\fLffff\fR
+-[3]     \fL0xxx\fR/\fL0\fR,\fL??\fR/\fL1\fR     \fL0xxx\fR/\fL0\fR,\fL??\fR/\fL1\fR     \fL1xxx\fR/\fLffff\fR,\fL--\fR  \fL1xxx\fR/\fL1fff\fR
+-[4]     \fL????\fR/\fL1\fR,\fL0y\fR/\fL0\fR     \fLfffe\fR/\fL0\fR,\fL0y\fR/\fL0\fR     \fL1000\fR/\fL1000\fR,\fL0y\fR  \fLz000\fR/\fLf000\fR
+-[5]     \fL0xxx\fR/\fL0\fR,\fL0y\fR/\fL0\fR     \fL0xxx\fR/\fL0\fR,\fL0y\fR/\fL0\fR     \fL1xxx\fR/\fLffff\fR,\fL0y\fR  \fLzxxx\fR/\fLffff\fR
++Criteria;OpenFlow 1.0;OpenFlow 1.1;OpenFlow 1.2+;NXM
++\_;\_;\_;\_;\_
++[1];\fL????\fR/\fL1\fR,\fL??\fR/\fL?\fR;\fL????\fR/\fL1\fR,\fL??\fR/\fL?\fR;\fL0000\fR/\fL0000\fR,\fL--\fR;\fL0000\fR/\fL0000\fR
++[2];\fLffff\fR/\fL0\fR,\fL??\fR/\fL?\fR;\fLffff\fR/\fL0\fR,\fL??\fR/\fL?\fR;\fL0000\fR/\fLffff\fR,\fL--\fR;\fL0000\fR/\fLffff\fR
++[3];\fL0xxx\fR/\fL0\fR,\fL??\fR/\fL1\fR;\fL0xxx\fR/\fL0\fR,\fL??\fR/\fL1\fR;\fL1xxx\fR/\fLffff\fR,\fL--\fR;\fL1xxx\fR/\fL1fff\fR
++[4];\fL????\fR/\fL1\fR,\fL0y\fR/\fL0\fR;\fLfffe\fR/\fL0\fR,\fL0y\fR/\fL0\fR;\fL1000\fR/\fL1000\fR,\fL0y\fR;\fLz000\fR/\fLf000\fR
++[5];\fL0xxx\fR/\fL0\fR,\fL0y\fR/\fL0\fR;\fL0xxx\fR/\fL0\fR,\fL0y\fR/\fL0\fR;\fL1xxx\fR/\fLffff\fR,\fL0y\fR;\fLzxxx\fR/\fLffff\fR
+ .T&amp;
+-r r c c r.
+-[6]     (none)  (none)  \fL1001\fR/\fL1001\fR,\fL--\fR  \fL1001\fR/\fL1001\fR
++r c c r r.
++[6];(none);(none);\fL1001\fR/\fL1001\fR,\fL--\fR;\fL1001\fR/\fL1001\fR
+ .T&amp;
+-r r c c c.
+-[7]     (none)  (none)  (none)  \fL3000\fR/\fL3000\fR
+-[8]     (none)  (none)  (none)  \fL0000\fR/\fL0fff\fR
+-[9]     (none)  (none)  (none)  \fL0000\fR/\fLf000\fR
+-[10]    (none)  (none)  (none)  \fL0000\fR/\fLefff\fR
++r c c c r.
++[7];(none);(none);(none);\fL3000\fR/\fL3000\fR
++[8];(none);(none);(none);\fL0000\fR/\fL0fff\fR
++[9];(none);(none);(none);\fL0000\fR/\fLf000\fR
++[10];(none);(none);(none);\fL0000\fR/\fLefff\fR
+     </tbl>
+ 
+     <p>
+@@ -4303,9 +4304,9 @@ r r c c c.
          <bits name="pln" above="8" below="4" width=".2"/>
          <bits name="op" above="16" width=".2" fill="yes"/>
          <bits name="sha" above="48" width="0.5" fill="yes"/>
@@ -63410,6 +63683,19 @@ index 0f222cc992..952fa902e4 100644
              ovsdb_jsonrpc_monitor_destroy(jm->jsonrpc_monitor, true);
          }
      }
+diff --git a/ovsdb/ovsdb-doc b/ovsdb/ovsdb-doc
+index 10d0c0c134..099770d253 100755
+--- a/ovsdb/ovsdb-doc
++++ b/ovsdb/ovsdb-doc
+@@ -24,7 +24,7 @@ import ovs.json
+ from ovs.db import error
+ import ovs.db.schema
+ 
+-from build.nroff import *
++from ovs_build_helpers.nroff import *
+ 
+ argv0 = sys.argv[0]
+ 
 diff --git a/ovsdb/ovsdb-idlc.in b/ovsdb/ovsdb-idlc.in
 index 10a70ae26f..13c5359395 100755
 --- a/ovsdb/ovsdb-idlc.in
@@ -64837,6 +65123,57 @@ index 726c138bf0..3a693855b9 100644
              json_destroy(txn_json);
              t->reply = jsonrpc_create_reply(json_object_create(),
                                              t->request->id);
+diff --git a/python/automake.mk b/python/automake.mk
+index 767512f175..3c369e03b8 100644
+--- a/python/automake.mk
++++ b/python/automake.mk
+@@ -45,9 +45,9 @@ ovs_pyfiles = \
+ # These python files are used at build time but not runtime,
+ # so they are not installed.
+ EXTRA_DIST += \
+-	python/build/__init__.py \
+-	python/build/nroff.py \
+-	python/build/soutil.py
++	python/ovs_build_helpers/__init__.py \
++	python/ovs_build_helpers/nroff.py \
++	python/ovs_build_helpers/soutil.py
+ 
+ # PyPI support.
+ EXTRA_DIST += \
+@@ -64,10 +64,11 @@ PYCOV_CLEAN_FILES += $(PYFILES:.py=.py,cover)
+ 
+ FLAKE8_PYFILES += \
+ 	$(filter-out python/ovs/compat/% python/ovs/dirs.py,$(PYFILES)) \
+-	python/setup.py \
+-	python/build/__init__.py \
+-	python/build/nroff.py \
+-	python/ovs/dirs.py.template
++	python/ovs_build_helpers/__init__.py \
++	python/ovs_build_helpers/nroff.py \
++	python/ovs_build_helpers/soutil.py \
++	python/ovs/dirs.py.template \
++	python/setup.py
+ 
+ nobase_pkgdata_DATA = $(ovs_pyfiles) $(ovstest_pyfiles)
+ ovs-install-data-local:
+@@ -86,11 +87,14 @@ ovs-install-data-local:
+ 	$(INSTALL_DATA) python/ovs/dirs.py.tmp $(DESTDIR)$(pkgdatadir)/python/ovs/dirs.py
+ 	rm python/ovs/dirs.py.tmp
+ 
++.PHONY: python-sdist
+ python-sdist: $(srcdir)/python/ovs/version.py $(ovs_pyfiles) python/ovs/dirs.py
+-	(cd python/ && $(PYTHON3) setup.py sdist)
++	cd python/ && $(PYTHON3) -m build --sdist
++
++.PHONY: pypi-upload
++pypi-upload: python-sdist
++	twine upload python/dist/ovs-$(VERSION).tar.gz
+ 
+-pypi-upload: $(srcdir)/python/ovs/version.py $(ovs_pyfiles) python/ovs/dirs.py
+-	(cd python/ && $(PYTHON3) setup.py sdist upload)
+ install-data-local: ovs-install-data-local
+ 
+ UNINSTALL_LOCAL += ovs-uninstall-local
 diff --git a/python/ovs/_json.c b/python/ovs/_json.c
 index ef7bb4b8ee..c36a140a8e 100644
 --- a/python/ovs/_json.c
@@ -65353,6 +65690,18 @@ index ac5b0fd0c6..b32341076c 100644
              return ovs.socket_util.get_exception_errno(e)
  
          return 0
+diff --git a/python/build/__init__.py b/python/ovs_build_helpers/__init__.py
+similarity index 100%
+rename from python/build/__init__.py
+rename to python/ovs_build_helpers/__init__.py
+diff --git a/python/build/nroff.py b/python/ovs_build_helpers/nroff.py
+similarity index 100%
+rename from python/build/nroff.py
+rename to python/ovs_build_helpers/nroff.py
+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/python/setup.py b/python/setup.py
 index cfe01763f3..36ced65089 100644
 --- a/python/setup.py
@@ -65487,6 +65836,18 @@ index 220e5c7472..8ee8a99c22 100644
  /usr/share/openvswitch/vswitch.ovsschema
  /usr/share/openvswitch/vtep.ovsschema
  %doc NOTICE README.rst NEWS rhel/README.RHEL.rst
+diff --git a/tests/.gitignore b/tests/.gitignore
+index a3d927e5d5..4c52fb2534 100644
+--- a/tests/.gitignore
++++ b/tests/.gitignore
+@@ -3,6 +3,7 @@
+ /Makefile.in
+ /atconfig
+ /atlocal
++/clang-analyzer-results/
+ /idltest.c
+ /idltest.h
+ /idltest.ovsidl
 diff --git a/tests/alb.at b/tests/alb.at
 index 2bef06f39c..922185d61d 100644
 --- a/tests/alb.at
@@ -72037,6 +72398,28 @@ index f639ba53a2..53c86ef2fd 100644
 +[
 +    AT_SKIP_IF([:])
 +])
+diff --git a/tests/test-barrier.c b/tests/test-barrier.c
+index 3bc5291cc1..fb0ab0e695 100644
+--- a/tests/test-barrier.c
++++ b/tests/test-barrier.c
+@@ -14,13 +14,13 @@
+  * limitations under the License.
+  */
+ 
+-#include <getopt.h>
+-
+ #include <config.h>
++#undef NDEBUG
++#include <getopt.h>
+ 
+-#include "ovs-thread.h"
+-#include "ovs-rcu.h"
+ #include "ovstest.h"
++#include "ovs-rcu.h"
++#include "ovs-thread.h"
+ #include "random.h"
+ #include "util.h"
+ 
 diff --git a/tests/test-cmap.c b/tests/test-cmap.c
 index 0705475606..588a5dea63 100644
 --- a/tests/test-cmap.c
@@ -72226,6 +72609,25 @@ index 9259b0b3fc..e50c7c3807 100644
  
          hmap_destroy(&hmap);
      }
+diff --git a/tests/test-id-fpool.c b/tests/test-id-fpool.c
+index 25275d9aef..27800aa9ba 100644
+--- a/tests/test-id-fpool.c
++++ b/tests/test-id-fpool.c
+@@ -14,12 +14,12 @@
+  * limitations under the License.
+  */
+ 
++#include <config.h>
+ #undef NDEBUG
+ #include <assert.h>
+ #include <getopt.h>
+ #include <string.h>
+-
+-#include <config.h>
++#include <sys/time.h>
+ 
+ #include "command-line.h"
+ #include "id-fpool.h"
 diff --git a/tests/test-json.c b/tests/test-json.c
 index 072a537252..fa51bb31c5 100644
 --- a/tests/test-json.c
@@ -72481,6 +72883,25 @@ index 6f1fb059bc..ac82f2048e 100644
          }
      }
  }
+diff --git a/tests/test-mpsc-queue.c b/tests/test-mpsc-queue.c
+index a38bf9e6df..16aa804a03 100644
+--- a/tests/test-mpsc-queue.c
++++ b/tests/test-mpsc-queue.c
+@@ -14,12 +14,12 @@
+  * limitations under the License.
+  */
+ 
++#include <config.h>
+ #undef NDEBUG
+ #include <assert.h>
+ #include <getopt.h>
+ #include <string.h>
+-
+-#include <config.h>
++#include <sys/time.h>
+ 
+ #include "command-line.h"
+ #include "guarded-list.h"
 diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c
 index ca4e87b811..cd1c31a6c2 100644
 --- a/tests/test-ovsdb.c
diff --git a/SPECS/openvswitch2.17.spec b/SPECS/openvswitch2.17.spec
index 8990a65..ac03700 100644
--- a/SPECS/openvswitch2.17.spec
+++ b/SPECS/openvswitch2.17.spec
@@ -57,7 +57,7 @@ Summary: Open vSwitch
 Group: System Environment/Daemons daemon/database/utilities
 URL: http://www.openvswitch.org/
 Version: 2.17.0
-Release: 103%{?dist}
+Release: 104%{?dist}
 
 # Nearly all of openvswitch is ASL 2.0.  The bugtool is LGPLv2+, and the
 # lib/sflow*.[ch] files are SISSL
@@ -751,6 +751,24 @@ exit 0
 %endif
 
 %changelog
+* Fri Aug 25 2023 Open vSwitch CI <ovs-ci@redhat.com> - 2.17.0-104
+- Merging upstream branch-2.17 [RH git: 46e94d6a61]
+    Commit list:
+    123b7aaa7c python: Use build to generate PEP517 compatible archives.
+    41d2e7e9a8 python: Use twine to upload sdist package to pypi.org.
+    66d5562e30 python: Rename build related code to ovs_build_helpers.
+    c880faea8e dpif-netdev: Fix length calculation of netdet_flow_key.
+    8c7aa5f589 doc: Fix description of max_len for controller action.
+    34ff03c3cb docs: Fix rendering of VLAN Comparison Chart.
+    93412e00e7 docs: Run tbl preprocessor in manpage-check rule.
+    6929485d31 docs: Add `nowarn` region option to tables.
+    08b6b83a36 tests: Add clang-analyzer-results to gitignore.
+    c252b1f8a7 ci: Add jobs to test -std=c99 builds.
+    242bb2624c tests: Fix order of includes in barrier/id-fpool/mpsc-queue tests.
+    292eca58c6 sflow: Always enable _BSD_SOURCE.
+    82aa3fb019 compiler.h: Don't use asm and typeof with non-GNU compilers.
+
+
 * Thu Aug 17 2023 Open vSwitch CI <ovs-ci@redhat.com> - 2.17.0-103
 - Merging upstream branch-2.17 [RH git: 04750e9ad1]
     Commit list: