diff --git a/SOURCES/openvswitch-2.17.0.patch b/SOURCES/openvswitch-2.17.0.patch
index 7ee044d..86a95e7 100644
--- a/SOURCES/openvswitch-2.17.0.patch
+++ b/SOURCES/openvswitch-2.17.0.patch
@@ -604,11 +604,610 @@ index 0c360fd1ef..c981f90bc7 100644
       [], [enable_sparse=no])
     AM_CONDITIONAL([ENABLE_SPARSE_BY_DEFAULT], [test $enable_sparse = yes])])
  
+diff --git a/build-aux/automake.mk b/build-aux/automake.mk
+index 6267ccd7cf..fa49e27b4a 100644
+--- a/build-aux/automake.mk
++++ b/build-aux/automake.mk
+@@ -1,9 +1,17 @@
+ EXTRA_DIST += \
+ 	build-aux/calculate-schema-cksum \
+ 	build-aux/cccl \
++	build-aux/check-structs \
+ 	build-aux/cksum-schema-check \
+ 	build-aux/dist-docs \
+ 	build-aux/dpdkstrip.py \
++	build-aux/extract-odp-netlink-h \
++	build-aux/extract-odp-netlink-macros-h \
++	build-aux/extract-odp-netlink-windows-dp-h \
++	build-aux/extract-ofp-actions \
++	build-aux/extract-ofp-errors \
++	build-aux/extract-ofp-fields \
++	build-aux/extract-ofp-msgs \
+ 	build-aux/generate-dhparams-c \
+ 	build-aux/initial-tab-allowed-files \
+ 	build-aux/sodepends.py \
+@@ -12,7 +20,11 @@ EXTRA_DIST += \
+ 	build-aux/xml2nroff
+ 
+ FLAKE8_PYFILES += \
+-    $(srcdir)/build-aux/xml2nroff \
+-    build-aux/dpdkstrip.py \
+-    build-aux/sodepends.py \
+-    build-aux/soexpand.py
++	build-aux/dpdkstrip.py \
++	build-aux/extract-ofp-actions \
++	build-aux/extract-ofp-errors \
++	build-aux/extract-ofp-fields \
++	build-aux/extract-ofp-msgs \
++	build-aux/sodepends.py \
++	build-aux/soexpand.py \
++	build-aux/xml2nroff
+diff --git a/build-aux/extract-ofp-actions b/build-aux/extract-ofp-actions
+index 0aa6c65f31..0c5be91bb5 100755
+--- a/build-aux/extract-ofp-actions
++++ b/build-aux/extract-ofp-actions
+@@ -17,27 +17,30 @@ version_map = {"1.0": 0x01,
+ version_reverse_map = dict((v, k) for (k, v) in version_map.items())
+ 
+ # Map from vendor name to the length of the action header.
+-vendor_map = {"OF": (0x00000000,  4),
++vendor_map = {"OF": (0x00000000, 4),
+               "ONF": (0x4f4e4600, 10),
+               "NX": (0x00002320, 10)}
+ 
+ # Basic types used in action arguments.
+-types = {}
+-types['uint8_t'] =  {"size": 1, "align": 1, "ntoh": None,     "hton": None}
+-types['ovs_be16'] = {"size": 2, "align": 2, "ntoh": "ntohs",  "hton": "htons"}
+-types['ovs_be32'] = {"size": 4, "align": 4, "ntoh": "ntohl",  "hton": "htonl"}
+-types['ovs_be64'] = {"size": 8, "align": 8, "ntoh": "ntohll", "hton": "htonll"}
+-types['uint16_t'] = {"size": 2, "align": 2, "ntoh": None,     "hton": None}
+-types['uint32_t'] = {"size": 4, "align": 4, "ntoh": None,     "hton": None}
+-types['uint64_t'] = {"size": 8, "align": 8, "ntoh": None,     "hton": None}
++types = {
++    "uint8_t": {"size": 1, "align": 1, "ntoh": None, "hton": None},
++    "ovs_be16": {"size": 2, "align": 2, "ntoh": "ntohs", "hton": "htons"},
++    "ovs_be32": {"size": 4, "align": 4, "ntoh": "ntohl", "hton": "htonl"},
++    "ovs_be64": {"size": 8, "align": 8, "ntoh": "ntohll", "hton": "htonll"},
++    "uint16_t": {"size": 2, "align": 2, "ntoh": None, "hton": None},
++    "uint32_t": {"size": 4, "align": 4, "ntoh": None, "hton": None},
++    "uint64_t": {"size": 8, "align": 8, "ntoh": None, "hton": None},
++}
+ 
+ line = ""
+-
++n_errors = 0
+ arg_structs = set()
+ 
++
+ def round_up(x, y):
+     return int((x + (y - 1)) / y) * y
+ 
++
+ def open_file(fn):
+     global file_name
+     global input_file
+@@ -46,6 +49,7 @@ def open_file(fn):
+     input_file = open(file_name)
+     line_number = 0
+ 
++
+ def get_line():
+     global input_file
+     global line
+@@ -56,16 +60,18 @@ def get_line():
+         fatal("unexpected end of input")
+     return line
+ 
+-n_errors = 0
++
+ def error(msg):
+     global n_errors
+     sys.stderr.write("%s:%d: %s\n" % (file_name, line_number, msg))
+     n_errors += 1
+ 
++
+ def fatal(msg):
+     error(msg)
+     sys.exit(1)
+ 
++
+ def usage():
+     argv0 = os.path.basename(sys.argv[0])
+     print('''\
+@@ -84,10 +90,8 @@ Commands:
+ ''' % {"argv0": argv0})
+     sys.exit(0)
+ 
+-def extract_ofp_actions(fn, definitions):
+-    error_types = {}
+ 
+-    comments = []
++def extract_ofp_actions(fn, definitions):
+     names = []
+     domain = {}
+     for code, size in vendor_map.values():
+@@ -100,14 +104,14 @@ def extract_ofp_actions(fn, definitions):
+ 
+     while True:
+         get_line()
+-        if re.match('enum ofp_raw_action_type {', line):
++        if re.match(r'enum ofp_raw_action_type {', line):
+             break
+ 
+     while True:
+         get_line()
+         if line.startswith('/*') or not line or line.isspace():
+             continue
+-        elif re.match('}', line):
++        elif re.match(r'}', line):
+             break
+ 
+         if not line.lstrip().startswith('/*'):
+@@ -119,10 +123,10 @@ def extract_ofp_actions(fn, definitions):
+             if line.startswith('/*') or not line or line.isspace():
+                 fatal("unexpected syntax within action")
+             comment += ' %s' % line.lstrip('* \t').rstrip(' \t\r\n')
+-        comment = re.sub('\[[^]]*\]', '', comment)
++        comment = re.sub(r'\[[^]]*\]', '', comment)
+         comment = comment[:-2].rstrip()
+ 
+-        m = re.match('([^:]+):\s+(.*)$', comment)
++        m = re.match(r'([^:]+):\s+(.*)$', comment)
+         if not m:
+             fatal("unexpected syntax between actions")
+ 
+@@ -147,7 +151,9 @@ def extract_ofp_actions(fn, definitions):
+         names.append(enum)
+ 
+         for dst in dsts.split(', '):
+-            m = re.match(r'([A-Z]+)([0-9.]+)(\+|-[0-9.]+)?(?:\((\d+)\))(?: is deprecated \(([^)]+)\))?$', dst)
++            m = re.match(
++                r'([A-Z]+)([0-9.]+)(\+|-[0-9.]+)?(?:\((\d+)\))(?:'
++                r' is deprecated \(([^)]+)\))?$', dst)
+             if not m:
+                 fatal("%r: syntax error in destination" % dst)
+             vendor_name = m.group(1)
+@@ -220,18 +226,18 @@ def extract_ofp_actions(fn, definitions):
+                     else:
+                         max_length = min_length
+ 
+-                    info = {"enum": enum,                     # 0
+-                            "deprecation": deprecation,       # 1
+-                            "file_name": file_name,           # 2
+-                            "line_number": line_number,       # 3
+-                            "min_length": min_length,         # 4
+-                            "max_length": max_length,         # 5
+-                            "arg_ofs": arg_ofs,               # 6
+-                            "arg_len": arg_len,               # 7
+-                            "base_argtype": base_argtype,     # 8
+-                            "arg_vl_mff_map": arg_vl_mff_map, # 9
+-                            "version": version,               # 10
+-                            "type": type_}                    # 11
++                    info = {"enum": enum,                      # 0
++                            "deprecation": deprecation,        # 1
++                            "file_name": file_name,            # 2
++                            "line_number": line_number,        # 3
++                            "min_length": min_length,          # 4
++                            "max_length": max_length,          # 5
++                            "arg_ofs": arg_ofs,                # 6
++                            "arg_len": arg_len,                # 7
++                            "base_argtype": base_argtype,      # 8
++                            "arg_vl_mff_map": arg_vl_mff_map,  # 9
++                            "version": version,                # 10
++                            "type": type_}                     # 11
+                     domain[vendor][type_][version] = info
+ 
+                     enums.setdefault(enum, [])
+@@ -247,9 +253,13 @@ def extract_ofp_actions(fn, definitions):
+ """)
+ 
+     if definitions:
+-        print("/* Verify that structs used as actions are reasonable sizes. */")
++        print(
++            "/* Verify that structs used as actions are reasonable sizes. */"
++        )
+         for s in sorted(arg_structs):
+-            print("BUILD_ASSERT_DECL(sizeof(%s) %% OFP_ACTION_ALIGN == 0);" % s)
++            print(
++                "BUILD_ASSERT_DECL(sizeof(%s) %% OFP_ACTION_ALIGN == 0);" % s
++            )
+ 
+         print("\nstatic struct ofpact_raw_instance all_raw_instances[] = {")
+         for vendor in domain:
+@@ -265,9 +275,11 @@ def extract_ofp_actions(fn, definitions):
+                     print("      %s," % d["max_length"])
+                     print("      %s," % d["arg_ofs"])
+                     print("      %s," % d["arg_len"])
+-                    print("      \"%s\"," % re.sub('_RAW[0-9]*', '', d["enum"], 1))
++                    print("      \"%s\","
++                          % re.sub(r'_RAW[0-9]*', '', d["enum"], 1))
+                     if d["deprecation"]:
+-                        print("      \"%s\"," % re.sub(r'(["\\])', r'\\\1', d["deprecation"]))
++                        print("      \"%s\","
++                              % re.sub(r'(["\\])', r'\\\1', d["deprecation"]))
+                     else:
+                         print("      NULL,")
+                     print("    },")
+@@ -286,10 +298,11 @@ def extract_ofp_actions(fn, definitions):
+ 
+         decl = "static inline "
+         if base_argtype.startswith('struct'):
+-            decl += "%s *" %base_argtype
++            decl += "%s *" % base_argtype
+         else:
+             decl += "void"
+-        decl += "\nput_%s(struct ofpbuf *openflow" % versions[0]["enum"].replace('_RAW', '', 1)
++        decl += "\nput_%s(struct ofpbuf *openflow" \
++                % versions[0]["enum"].replace('_RAW', '', 1)
+         if need_ofp_version:
+             decl += ", enum ofp_version version"
+         if base_argtype != 'void' and not base_argtype.startswith('struct'):
+@@ -348,9 +361,13 @@ ofpact_decode(const struct ofp_action_header *a, enum ofp_raw_action_type raw,
+                     else:
+                         arg = "arg"
+                 if arg_vl_mff_map:
+-                    print("        return decode_%s(%s, version, vl_mff_map, tlv_bitmap, out);" % (enum, arg))
++                    print(
++                        "        return decode_%s(%s," % (enum, arg),
++                        "version, vl_mff_map, tlv_bitmap, out);"
++                    )
+                 else:
+-                    print("        return decode_%s(%s, version, out);" % (enum, arg))
++                    print("        return decode_%s(%s, version, out);"
++                          % (enum, arg))
+             print("")
+         print("""\
+     default:
+@@ -366,7 +383,8 @@ ofpact_decode(const struct ofp_action_header *a, enum ofp_raw_action_type raw,
+             arg_vl_mff_map = versions[0]["arg_vl_mff_map"]
+             if base_argtype != 'void':
+                 if base_argtype.startswith('struct'):
+-                    prototype += "const %s *, enum ofp_version, " % base_argtype
++                    prototype += "const %s *, " % base_argtype
++                    prototype += "enum ofp_version, "
+                 else:
+                     prototype += "%s, enum ofp_version, " % base_argtype
+                 if arg_vl_mff_map:
+@@ -378,13 +396,15 @@ ofpact_decode(const struct ofp_action_header *a, enum ofp_raw_action_type raw,
+ static enum ofperr ofpact_decode(const struct ofp_action_header *,
+                                  enum ofp_raw_action_type raw,
+                                  enum ofp_version version,
+-                                 uint64_t arg, const struct vl_mff_map *vl_mff_map,
++                                 uint64_t arg,
++                                 const struct vl_mff_map *vl_mff_map,
+                                  uint64_t *tlv_bitmap, struct ofpbuf *out);
+ """)
++
+ 
+-## ------------ ##
+-## Main Program ##
+-## ------------ ##
++# ------------ #
++# Main Program #
++# ------------ #
+ 
+ if __name__ == '__main__':
+     argv0 = sys.argv[0]
+diff --git a/build-aux/extract-ofp-errors b/build-aux/extract-ofp-errors
+index 2c3fbfc881..eeefccbee0 100755
+--- a/build-aux/extract-ofp-errors
++++ b/build-aux/extract-ofp-errors
+@@ -22,6 +22,9 @@ tokenRe = "#?" + idRe + "|[0-9]+|."
+ inComment = False
+ inDirective = False
+ 
++n_errors = 0
++
++
+ def open_file(fn):
+     global fileName
+     global inputFile
+@@ -30,6 +33,7 @@ def open_file(fn):
+     inputFile = open(fileName)
+     lineNumber = 0
+ 
++
+ def tryGetLine():
+     global inputFile
+     global line
+@@ -38,10 +42,12 @@ def tryGetLine():
+     lineNumber += 1
+     return line != ""
+ 
++
+ def getLine():
+     if not tryGetLine():
+         fatal("unexpected end of input")
+ 
++
+ def getToken():
+     global token
+     global line
+@@ -82,37 +88,43 @@ def getToken():
+                 line = line[:-2] + inputFile.readline()
+                 lineNumber += 1
+             if line == "":
+-                if token == None:
++                if token is None:
+                     fatal("unexpected end of input")
+                 token = None
+                 return False
+ 
+-n_errors = 0
++
+ def error(msg):
+     global n_errors
+     sys.stderr.write("%s:%d: %s\n" % (fileName, lineNumber, msg))
+     n_errors += 1
+ 
++
+ def fatal(msg):
+     error(msg)
+     sys.exit(1)
+ 
++
+ def skipDirective():
+     getToken()
+     while token != '$':
+         getToken()
+ 
++
+ def isId(s):
+-    return re.match(idRe + "$", s) != None
++    return re.match(idRe + "$", s) is not None
++
+ 
+ def forceId():
+     if not isId(token):
+         fatal("identifier expected")
+ 
++
+ def forceInteger():
+-    if not re.match('[0-9]+$', token):
++    if not re.match(r'[0-9]+$', token):
+         fatal("integer expected")
+ 
++
+ def match(t):
+     if token == t:
+         getToken()
+@@ -120,10 +132,12 @@ def match(t):
+     else:
+         return False
+ 
++
+ def forceMatch(t):
+     if not match(t):
+         fatal("%s expected" % t)
+ 
++
+ def parseTaggedName():
+     assert token in ('struct', 'union')
+     name = token
+@@ -133,26 +147,26 @@ def parseTaggedName():
+     getToken()
+     return name
+ 
++
+ def print_enum(tag, constants, storage_class):
+-    print ("""
++    print("""
+ %(storage_class)sconst char *
+ %(tag)s_to_string(uint16_t value)
+ {
+     switch (value) {\
+ """ % {"tag": tag,
+-       "bufferlen": len(tag) + 32,
+        "storage_class": storage_class})
+     for constant in constants:
+-        print ("    case %s: return \"%s\";" % (constant, constant))
+-    print ("""\
++        print("    case %s: return \"%s\";" % (constant, constant))
++    print("""\
+     }
+     return NULL;
+-}\
+-""" % {"tag": tag})
++}""")
++
+ 
+ def usage():
+     argv0 = os.path.basename(sys.argv[0])
+-    print ('''\
++    print('''\
+ %(argv0)s, for extracting OpenFlow error codes from header files
+ usage: %(argv0)s ERROR_HEADER VENDOR_HEADER
+ 
+@@ -167,6 +181,7 @@ The output is suitable for use as lib/ofp-errors.inc.\
+ ''' % {"argv0": argv0})
+     sys.exit(0)
+ 
++
+ def extract_vendor_ids(fn):
+     global vendor_map
+     vendor_map = {}
+@@ -174,7 +189,10 @@ def extract_vendor_ids(fn):
+ 
+     open_file(fn)
+     while tryGetLine():
+-        m = re.match(r'#define\s+([A-Z0-9_]+)_VENDOR_ID\s+(0x[0-9a-fA-F]+|[0-9]+)', line)
++        m = re.match(
++            r'#define\s+([A-Z0-9_]+)_VENDOR_ID\s+(0x[0-9a-fA-F]+|[0-9]+)',
++            line
++        )
+         if not m:
+             continue
+ 
+@@ -202,9 +220,8 @@ def extract_vendor_ids(fn):
+                   % (id_, vendor_reverse_map[id_], name))
+         vendor_reverse_map[id_] = name
+ 
+-def extract_ofp_errors(fn):
+-    error_types = {}
+ 
++def extract_ofp_errors(fn):
+     comments = []
+     names = []
+     domain = {}
+@@ -220,14 +237,14 @@ def extract_ofp_errors(fn):
+ 
+     while True:
+         getLine()
+-        if re.match('enum ofperr', line):
++        if re.match(r'enum ofperr', line):
+             break
+ 
+     while True:
+         getLine()
+         if line.startswith('/*') or not line or line.isspace():
+             continue
+-        elif re.match('}', line):
++        elif re.match(r'}', line):
+             break
+ 
+         if not line.lstrip().startswith('/*'):
+@@ -241,19 +258,19 @@ def extract_ofp_errors(fn):
+             comment += ' %s' % line.lstrip('* \t').rstrip(' \t\r\n')
+         comment = comment[:-2].rstrip()
+ 
+-        m = re.match('Expected: (.*)\.$', comment)
++        m = re.match(r'Expected: (.*)\.$', comment)
+         if m:
+             expected_errors[m.group(1)] = (fileName, lineNumber)
+             continue
+ 
+-        m = re.match('((?:.(?!\.  ))+.)\.\s+(.*)$', comment)
++        m = re.match(r'((?:.(?!\.  ))+.)\.\s+(.*)$', comment)
+         if not m:
+             fatal("unexpected syntax between errors")
+ 
+         dsts, comment = m.groups()
+ 
+         getLine()
+-        m = re.match('\s+(?:OFPERR_([A-Z0-9_]+))(\s*=\s*OFPERR_OFS)?,',
++        m = re.match(r'\s+(?:OFPERR_([A-Z0-9_]+))(\s*=\s*OFPERR_OFS)?,',
+                      line)
+         if not m:
+             fatal("syntax error expecting OFPERR_ enum value")
+@@ -262,11 +279,14 @@ def extract_ofp_errors(fn):
+         if enum in names:
+             fatal("%s specified twice" % enum)
+ 
+-        comments.append(re.sub('\[[^]]*\]', '', comment))
++        comments.append(re.sub(r'\[[^]]*\]', '', comment))
+         names.append(enum)
+ 
+         for dst in dsts.split(', '):
+-            m = re.match(r'([A-Z]+)([0-9.]+)(\+|-[0-9.]+)?\((\d+)(?:,(\d+))?\)$', dst)
++            m = re.match(
++                r'([A-Z]+)([0-9.]+)(\+|-[0-9.]+)?\((\d+)(?:,(\d+))?\)$',
++                dst
++            )
+             if not m:
+                 fatal("%r: syntax error in destination" % dst)
+             vendor_name = m.group(1)
+@@ -313,8 +333,7 @@ def extract_ofp_errors(fn):
+                 # mechanism that includes a type but not a code.
+                 if v1 < version_map['1.2'] or v2 < version_map['1.2']:
+                     if code is None:
+-                        fatal("%s: NX1.0 and NX1.1 domains require code"
+-                              % (dst, vendor_name))
++                        fatal("%s: NX1.0 and NX1.1 domains require code" % dst)
+                 if v1 >= version_map['1.2'] or v2 >= version_map['1.2']:
+                     if code is not None:
+                         fatal("%s: NX1.2+ domains do not have codes" % dst)
+@@ -340,11 +359,13 @@ def extract_ofp_errors(fn):
+                         del expected_errors[msg]
+                     else:
+                         error("%s: %s." % (dst, msg))
+-                        sys.stderr.write("%s:%d: %s: Here is the location "
+-                                         "of the previous definition.\n"
+-                                         % (domain[version][vendor][type_][code][1],
+-                                            domain[version][vendor][type_][code][2],
+-                                            dst))
++                        sys.stderr.write(
++                            "%s:%d: %s: Here is the location "
++                            "of the previous definition.\n"
++                            % (domain[version][vendor][type_][code][1],
++                               domain[version][vendor][type_][code][2],
++                               dst)
++                        )
+                 else:
+                     domain[version][vendor][type_][code] = (enum, fileName,
+                                                    lineNumber)
+@@ -361,7 +382,7 @@ def extract_ofp_errors(fn):
+     if n_errors:
+         sys.exit(1)
+ 
+-    print ("""\
++    print("""\
+ /* Generated automatically; do not modify!     -*- buffer-read-only: t -*- */
+ 
+ #define OFPERR_N_ERRORS %d
+@@ -386,7 +407,7 @@ static const char *error_comments[OFPERR_N_ERRORS] = {
+                  for comment in comments)))
+ 
+     def output_domain(map, name, description, version):
+-        print ("""
++        print("""
+ static enum ofperr
+ %s_decode(uint32_t vendor, uint16_t type, uint16_t code)
+ {
+@@ -405,16 +426,16 @@ static enum ofperr
+                 vendor_s = "(%#xULL << 32) | " % vendor
+             else:
+                 vendor_s = ""
+-            print ("    case %s ((uint32_t) %d << 16) | %d:" % (vendor_s,
++            print("    case %s ((uint32_t) %d << 16) | %d:" % (vendor_s,
+                                                                type_, code))
+-            print ("        return OFPERR_%s;" % enum)
+-        print ("""\
++            print("        return OFPERR_%s;" % enum)
++        print("""\
+     }
+ 
+     return 0;
+ }""")
+ 
+-        print ("""
++        print("""
+ static const struct ofperr_domain %s = {
+     "%s",
+     %d,
+@@ -423,20 +444,22 @@ static const struct ofperr_domain %s = {
+         for enum in names:
+             if enum in map:
+                 vendor, type_, code = map[enum]
+-                if code == None:
++                if code is None:
+                     code = -1
+-                print ("        { %#8x, %2d, %3d }, /* %s */" % (vendor, type_, code, enum))
++                print("        { %#8x, %2d, %3d }, /* %s */" % (vendor, type_,
++                                                                code, enum))
+             else:
+-                print ("        {       -1, -1,  -1 }, /* %s */" % enum)
+-        print ("""\
++                print("        {       -1, -1,  -1 }, /* %s */" % enum)
++        print("""\
+     },
+ };""")
+ 
+     for version_name, id_ in version_map.items():
+-        var = 'ofperr_of' + re.sub('[^A-Za-z0-9_]', '', version_name)
++        var = 'ofperr_of' + re.sub(r'[^A-Za-z0-9_]', '', version_name)
+         description = "OpenFlow %s" % version_name
+         output_domain(reverse[id_], var, description, id_)
+ 
++
+ if __name__ == '__main__':
+     if '--help' in sys.argv:
+         usage()
 diff --git a/build-aux/extract-ofp-fields b/build-aux/extract-ofp-fields
-index 8766995d9a..9fb4df98ad 100755
+index 8766995d9a..76702bfa81 100755
 --- a/build-aux/extract-ofp-fields
 +++ b/build-aux/extract-ofp-fields
-@@ -5,7 +5,8 @@ import sys
+@@ -5,58 +5,67 @@ import sys
  import os.path
  import re
  import xml.dom.minidom
@@ -618,25 +1217,333 @@ index 8766995d9a..9fb4df98ad 100755
  
  line = ""
  
-@@ -578,7 +579,7 @@ def field_to_xml(field_node, f, body, summary):
-     body += [""".PP
- \\fB%s Field\\fR
+ # Maps from user-friendly version number to its protocol encoding.
+-VERSION = {"1.0": 0x01,
+-           "1.1": 0x02,
+-           "1.2": 0x03,
+-           "1.3": 0x04,
+-           "1.4": 0x05,
+-           "1.5": 0x06}
+-VERSION_REVERSE = dict((v,k) for k, v in VERSION.items())
+-
+-TYPES = {"u8":       (1,   False),
+-         "be16":     (2,   False),
+-         "be32":     (4,   False),
+-         "MAC":      (6,   False),
+-         "be64":     (8,   False),
+-         "be128":    (16,  False),
+-         "tunnelMD": (124, True)}
+-
+-FORMATTING = {"decimal":            ("MFS_DECIMAL",      1,   8),
+-              "hexadecimal":        ("MFS_HEXADECIMAL",  1, 127),
+-              "ct state":           ("MFS_CT_STATE",     4,   4),
+-              "Ethernet":           ("MFS_ETHERNET",     6,   6),
+-              "IPv4":               ("MFS_IPV4",         4,   4),
+-              "IPv6":               ("MFS_IPV6",        16,  16),
+-              "OpenFlow 1.0 port":  ("MFS_OFP_PORT",     2,   2),
+-              "OpenFlow 1.1+ port": ("MFS_OFP_PORT_OXM", 4,   4),
+-              "frag":               ("MFS_FRAG",         1,   1),
+-              "tunnel flags":       ("MFS_TNL_FLAGS",    2,   2),
+-              "TCP flags":          ("MFS_TCP_FLAGS",    2,   2),
+-              "packet type":        ("MFS_PACKET_TYPE",  4,   4)}
+-
+-PREREQS = {"none": "MFP_NONE",
+-           "Ethernet": "MFP_ETHERNET",
+-           "ARP": "MFP_ARP",
+-           "VLAN VID": "MFP_VLAN_VID",
+-           "IPv4": "MFP_IPV4",
+-           "IPv6": "MFP_IPV6",
+-           "IPv4/IPv6": "MFP_IP_ANY",
+-           "NSH": "MFP_NSH",
+-           "CT": "MFP_CT_VALID",
+-           "MPLS": "MFP_MPLS",
+-           "TCP": "MFP_TCP",
+-           "UDP": "MFP_UDP",
+-           "SCTP": "MFP_SCTP",
+-           "ICMPv4": "MFP_ICMPV4",
+-           "ICMPv6": "MFP_ICMPV6",
+-           "ND": "MFP_ND",
+-           "ND solicit": "MFP_ND_SOLICIT",
+-           "ND advert": "MFP_ND_ADVERT"}
++VERSION = {
++    "1.0": 0x01,
++    "1.1": 0x02,
++    "1.2": 0x03,
++    "1.3": 0x04,
++    "1.4": 0x05,
++    "1.5": 0x06,
++}
++VERSION_REVERSE = dict((v, k) for k, v in VERSION.items())
++
++TYPES = {
++    "u8": (1, False),
++    "be16": (2, False),
++    "be32": (4, False),
++    "MAC": (6, False),
++    "be64": (8, False),
++    "be128": (16, False),
++    "tunnelMD": (124, True),
++}
++
++FORMATTING = {
++    "decimal": ("MFS_DECIMAL", 1, 8),
++    "hexadecimal": ("MFS_HEXADECIMAL", 1, 127),
++    "ct state": ("MFS_CT_STATE", 4, 4),
++    "Ethernet": ("MFS_ETHERNET", 6, 6),
++    "IPv4": ("MFS_IPV4", 4, 4),
++    "IPv6": ("MFS_IPV6", 16, 16),
++    "OpenFlow 1.0 port": ("MFS_OFP_PORT", 2, 2),
++    "OpenFlow 1.1+ port": ("MFS_OFP_PORT_OXM", 4, 4),
++    "frag": ("MFS_FRAG", 1, 1),
++    "tunnel flags": ("MFS_TNL_FLAGS", 2, 2),
++    "TCP flags": ("MFS_TCP_FLAGS", 2, 2),
++    "packet type": ("MFS_PACKET_TYPE", 4, 4),
++}
++
++PREREQS = {
++    "none": "MFP_NONE",
++    "Ethernet": "MFP_ETHERNET",
++    "ARP": "MFP_ARP",
++    "VLAN VID": "MFP_VLAN_VID",
++    "IPv4": "MFP_IPV4",
++    "IPv6": "MFP_IPV6",
++    "IPv4/IPv6": "MFP_IP_ANY",
++    "NSH": "MFP_NSH",
++    "CT": "MFP_CT_VALID",
++    "MPLS": "MFP_MPLS",
++    "TCP": "MFP_TCP",
++    "UDP": "MFP_UDP",
++    "SCTP": "MFP_SCTP",
++    "ICMPv4": "MFP_ICMPV4",
++    "ICMPv6": "MFP_ICMPV6",
++    "ND": "MFP_ND",
++    "ND solicit": "MFP_ND_SOLICIT",
++    "ND advert": "MFP_ND_ADVERT",
++}
+ 
+ # Maps a name prefix into an (experimenter ID, class) pair, so:
+ #
+@@ -65,20 +74,22 @@ PREREQS = {"none": "MFP_NONE",
+ #      - Experimenter OXM classes are written as (<oxm_vender>, 0xffff)
+ #
+ # If a name matches more than one prefix, the longest one is used.
+-OXM_CLASSES = {"NXM_OF_":        (0,          0x0000, 'extension'),
+-               "NXM_NX_":        (0,          0x0001, 'extension'),
+-               "NXOXM_NSH_":     (0x005ad650, 0xffff, 'extension'),
+-               "OXM_OF_":        (0,          0x8000, 'standard'),
+-               "OXM_OF_PKT_REG": (0,          0x8001, 'standard'),
+-               "ONFOXM_ET_":     (0x4f4e4600, 0xffff, 'standard'),
+-               "ERICOXM_OF_":    (0,          0x1000, 'extension'),
+-
+-               # This is the experimenter OXM class for Nicira, which is the
+-               # one that OVS would be using instead of NXM_OF_ and NXM_NX_
+-               # if OVS didn't have those grandfathered in.  It is currently
+-               # used only to test support for experimenter OXM, since there
+-               # are barely any real uses of experimenter OXM in the wild.
+-               "NXOXM_ET_":      (0x00002320, 0xffff, 'extension')}
++OXM_CLASSES = {
++    "NXM_OF_": (0, 0x0000, "extension"),
++    "NXM_NX_": (0, 0x0001, "extension"),
++    "NXOXM_NSH_": (0x005AD650, 0xFFFF, "extension"),
++    "OXM_OF_": (0, 0x8000, "standard"),
++    "OXM_OF_PKT_REG": (0, 0x8001, "standard"),
++    "ONFOXM_ET_": (0x4F4E4600, 0xFFFF, "standard"),
++    "ERICOXM_OF_": (0, 0x1000, "extension"),
++    # This is the experimenter OXM class for Nicira, which is the
++    # one that OVS would be using instead of NXM_OF_ and NXM_NX_
++    # if OVS didn't have those grandfathered in.  It is currently
++    # used only to test support for experimenter OXM, since there
++    # are barely any real uses of experimenter OXM in the wild.
++    "NXOXM_ET_": (0x00002320, 0xFFFF, "extension"),
++}
++
+ 
+ def oxm_name_to_class(name):
+     prefix = ''
+@@ -163,7 +174,10 @@ match_types = dict()
+ def parse_oxm(s, prefix, n_bytes):
+     global match_types
+ 
+-    m = re.match('([A-Z0-9_]+)\(([0-9]+)\) since(?: OF(1\.[0-9]+) and)? v([12]\.[0-9]+)$', s)
++    m = re.match(
++        r'([A-Z0-9_]+)\(([0-9]+)\) since(?: OF(1\.[0-9]+) and)? v([12]\.[0-9]+)$',  # noqa: E501
++        s
++    )
+     if not m:
+         fatal("%s: syntax error parsing %s" % (s, prefix))
+ 
+@@ -210,7 +224,8 @@ def parse_field(mff, comment):
+     f = {'mff': mff}
+ 
+     # First line of comment is the field name.
+-    m = re.match(r'"([^"]+)"(?:\s+\(aka "([^"]+)"\))?(?:\s+\(.*\))?\.', comment[0])
++    m = re.match(r'"([^"]+)"(?:\s+\(aka "([^"]+)"\))?(?:\s+\(.*\))?\.',
++                 comment[0])
+     if not m:
+         fatal("%s lacks field name" % mff)
+     f['name'], f['extra_name'] = m.groups()
+@@ -322,8 +337,11 @@ def protocols_to_c(protocols):
+ 
+ def autogen_c_comment():
+     return [
+-"/* Generated automatically; do not modify!    -*- buffer-read-only: t -*- */",
+-""]
++        "/* Generated automatically; do not modify!    "
++        "-*- buffer-read-only: t -*- */",
++        "",
++    ]
++
+ 
+ def make_meta_flow(meta_flow_h):
+     fields = extract_ofp_fields(meta_flow_h)
+@@ -432,20 +450,18 @@ def extract_ofp_fields(fn):
+ 
+     while True:
+         get_line()
+-        if re.match('enum.*mf_field_id', line):
++        if re.match(r'enum.*mf_field_id', line):
+             break
+ 
+     while True:
+         get_line()
+-        first_line_number = line_number
+-        here = '%s:%d' % (file_name, line_number)
+         if (line.startswith('/*')
+             or line.startswith(' *')
+             or line.startswith('#')
+             or not line
+             or line.isspace()):
+             continue
+-        elif re.match('}', line) or re.match('\s+MFF_N_IDS', line):
++        elif re.match(r'}', line) or re.match(r'\s+MFF_N_IDS', line):
+             break
+ 
+         # Parse the comment preceding an MFF_ constant into 'comment',
+@@ -494,7 +510,7 @@ def extract_ofp_fields(fn):
+         # Parse the MFF_ constant(s).
+         mffs = []
+         while True:
+-            m = re.match('\s+(MFF_[A-Z0-9_]+),?\s?$', line)
++            m = re.match(r'\s+(MFF_[A-Z0-9_]+),?\s?$', line)
+             if not m:
+                 break
+             mffs += [m.group(1)]
+@@ -505,7 +521,7 @@ def extract_ofp_fields(fn):
+         if len(mffs) > 1 or '<N>' in comment[0]:
+             for mff in mffs:
+                 # Extract trailing integer.
+-                m = re.match('.*[^0-9]([0-9]+)$', mff)
++                m = re.match(r'.*[^0-9]([0-9]+)$', mff)
+                 if not m:
+                     fatal("%s lacks numeric suffix in register group" % mff)
+                 n = m.group(1)
+@@ -515,10 +531,10 @@ def extract_ofp_fields(fn):
+                 instance = []
+                 for x in comment:
+                     y = x.replace('<N>', n)
+-                    if re.search('<[0-9]+>', y):
++                    if re.search(r'<[0-9]+>', y):
+                         if ('<%s>' % n) not in y:
+                             continue
+-                        y = re.sub('<[0-9]+>', '', y)
++                        y = re.sub(r'<[0-9]+>', '', y)
+                     instance += [y.strip()]
+                 fields += [parse_field(mff, instance)]
+         else:
+@@ -532,9 +548,10 @@ def extract_ofp_fields(fn):
+ 
+     return fields
+ 
+-## ------------------------ ##
+-## Documentation Generation ##
+-## ------------------------ ##
++# ------------------------ #
++# Documentation Generation #
++# ------------------------ #
++
+ 
+ def field_to_xml(field_node, f, body, summary):
+     f["used"] = True
+@@ -552,9 +569,9 @@ def field_to_xml(field_node, f, body, summary):
+         ovs_version = [int(x) for x in ovs_version_s.split('.')]
+         if min_ovs_version is None or ovs_version < min_ovs_version:
+             min_ovs_version = ovs_version
+-    summary += ["\\fB%s\\fR" % f["name"]]
++    summary += [r"\fB%s\fR" % f["name"]]
+     if f["extra_name"]:
+-        summary += [" aka \\fB%s\\fR" % f["extra_name"]]
++        summary += [r" aka \fB%s\fR" % f["extra_name"]]
+     summary += [";%d" % f["n_bytes"]]
+     if f["n_bits"] != 8 * f["n_bytes"]:
+         summary += [" (low %d bits)" % f["n_bits"]]
+@@ -575,16 +592,16 @@ def field_to_xml(field_node, f, body, summary):
+ 
+     title = field_node.attributes['title'].nodeValue
+ 
+-    body += [""".PP
+-\\fB%s Field\\fR
++    body += [r""".PP
++\fB%s Field\fR
  .TS
 -tab(;);
 +tab(;),nowarn;
  l lx.
  """ % title]
  
-@@ -636,7 +637,7 @@ l lx.
+-    body += ["Name:;\\fB%s\\fR" % f["name"]]
++    body += [r"Name:;\fB%s\fR" % f["name"]]
+     if f["extra_name"]:
+-        body += [" (aka \\fB%s\\fR)" % f["extra_name"]]
++        body += [r" (aka \fB%s\fR)" % f["extra_name"]]
+     body += ['\n']
+ 
+     body += ["Width:;"]
+@@ -619,16 +636,30 @@ l lx.
+     body += ["OpenFlow 1.1:;%s\n" % of11[f["OF1.1"]]]
+ 
+     oxms = []
+-    for header, name, of_version_nr, ovs_version in [x for x in sorted(f['OXM'], key=lambda x: x[2]) if is_standard_oxm(x[1])]:
++    for header, name, of_version_nr, ovs_version in [
++        x
++        for x in sorted(f['OXM'], key=lambda x: x[2])
++        if is_standard_oxm(x[1])
++    ]:
+         of_version = VERSION_REVERSE[of_version_nr]
+-        oxms += [r"\fB%s\fR (%d) since OpenFlow %s and Open vSwitch %s" % (name, header[2], of_version, ovs_version)]
++        oxms += [
++            r"\fB%s\fR (%d) since OpenFlow %s and Open vSwitch %s"
++            % (name, header[2], of_version, ovs_version)
++        ]
+     if not oxms:
+         oxms = ['none']
+     body += ['OXM:;T{\n%s\nT}\n' % r'\[char59] '.join(oxms)]
+ 
+     nxms = []
+-    for header, name, of_version_nr, ovs_version in [x for x in sorted(f['OXM'], key=lambda x: x[2]) if not is_standard_oxm(x[1])]:
+-        nxms += [r"\fB%s\fR (%d) since Open vSwitch %s" % (name, header[2], ovs_version)]
++    for header, name, of_version_nr, ovs_version in [
++        x
++        for x in sorted(f['OXM'], key=lambda x: x[2])
++        if not is_standard_oxm(x[1])
++    ]:
++        nxms += [
++            r"\fB%s\fR (%d) since Open vSwitch %s"
++            % (name, header[2], ovs_version)
++        ]
+     if not nxms:
+         nxms = ['none']
+     body += ['NXM:;T{\n%s\nT}\n' % r'\[char59] '.join(nxms)]
+@@ -636,7 +667,8 @@ 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):
+@@ -648,24 +680,27 @@ def group_xml_to_nroff(group_node, fields):
              id_ = node.attributes['id'].nodeValue
              field_to_xml(node, fields[id_], body, summary)
          else:
@@ -653,17 +1560,97 @@ index 8766995d9a..9fb4df98ad 100755
 +        '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):
+-        '\_;\_;\_;\_;\_;\_\n']
++        r'\_;\_;\_;\_;\_;\_',
++        '\n',
++    ]
+     content += summary
+     content += ['.TE\n']
+     content += body
      return ''.join(content)
  
++
  def make_oxm_classes_xml(document):
 -    s = '''tab(;);
-+    s = '''tab(;),nowarn;
++    s = r'''tab(;),nowarn;
  l l l.
  Prefix;Vendor;Class
  \_;\_;\_
-@@ -753,7 +754,7 @@ ovs\-fields \- protocol header fields in OpenFlow and Open vSwitch
+@@ -683,6 +718,7 @@ Prefix;Vendor;Class
+     e.appendChild(document.createTextNode(s))
+     return e
+ 
++
+ def recursively_replace(node, name, replacement):
+     for child in node.childNodes:
+         if child.nodeType == node.ELEMENT_NODE:
+@@ -691,6 +727,7 @@ def recursively_replace(node, name, replacement):
+             else:
+                 recursively_replace(child, name, replacement)
+ 
++
+ def make_ovs_fields(meta_flow_h, meta_flow_xml):
+     fields = extract_ofp_fields(meta_flow_h)
+     fields_map = {}
+@@ -701,46 +738,45 @@ def make_ovs_fields(meta_flow_h, meta_flow_xml):
+     doc = document.documentElement
+ 
+     global version
+-    if version == None:
++    if version is None:
+         version = "UNKNOWN"
+ 
+-    print('''\
+-'\\" tp
+-.\\" -*- mode: troff; coding: utf-8 -*-
++    print(r"""'\" tp
++.\" -*- mode: troff; coding: utf-8 -*-
+ .TH "ovs\-fields" 7 "%s" "Open vSwitch" "Open vSwitch Manual"
+-.fp 5 L CR              \\" Make fixed-width font available as \\fL.
++.fp 5 L CR              \" Make fixed-width font available as \fL.
+ .de ST
+ .  PP
+ .  RS -0.15in
+-.  I "\\\\$1"
++.  I "\\$1"
+ .  RE
+ ..
+ 
+ .de SU
+ .  PP
+-.  I "\\\\$1"
++.  I "\\$1"
+ ..
+ 
+ .de IQ
+ .  br
+ .  ns
+-.  IP "\\\\$1"
++.  IP "\\$1"
+ ..
+ 
+ .de TQ
+ .  br
+ .  ns
+-.  TP "\\\\$1"
++.  TP "\\$1"
+ ..
+ .de URL
+-\\\\$2 \\(laURL: \\\\$1 \\(ra\\\\$3
++\\$2 \(laURL: \\$1 \(ra\\$3
+ ..
+-.if \\n[.g] .mso www.tmac
++.if \n[.g] .mso www.tmac
+ .SH NAME
+ ovs\-fields \- protocol header fields in OpenFlow and Open vSwitch
+ .
+ .PP
+-''' % version)
++""" % version)
+ 
+     recursively_replace(doc, 'oxm_classes', make_oxm_classes_xml(document))
+ 
+@@ -753,7 +789,7 @@ ovs\-fields \- protocol header fields in OpenFlow and Open vSwitch
          elif node.nodeType == node.COMMENT_NODE:
              pass
          else:
@@ -672,6 +1659,126 @@ index 8766995d9a..9fb4df98ad 100755
  
      for f in fields:
          if "used" not in f:
+@@ -789,9 +825,10 @@ ovs\-fields \- protocol header fields in OpenFlow and Open vSwitch
+         if output[i] is not None:
+             print(output[i])
+ 
+-## ------------ ##
+-## Main Program ##
+-## ------------ ##
++# ------------ #
++# Main Program #
++# ------------ #
++
+ 
+ if __name__ == "__main__":
+     argv0 = sys.argv[0]
+diff --git a/build-aux/extract-ofp-msgs b/build-aux/extract-ofp-msgs
+index 6b3295cf64..c26ea1d355 100755
+--- a/build-aux/extract-ofp-msgs
++++ b/build-aux/extract-ofp-msgs
+@@ -24,6 +24,9 @@ OFPT11_STATS_REQUEST = 18
+ OFPT11_STATS_REPLY = 19
+ OFPST_VENDOR = 0xffff
+ 
++n_errors = 0
++
++
+ def decode_version_range(range):
+     if range in VERSION:
+         return (VERSION[range], VERSION[range])
+@@ -35,6 +38,7 @@ def decode_version_range(range):
+         a, b = re.match(r'^([^-]+)-([^-]+)$', range).groups()
+         return (VERSION[a], VERSION[b])
+ 
++
+ def get_line():
+     global line
+     global line_number
+@@ -43,16 +47,18 @@ def get_line():
+     if line == "":
+         fatal("unexpected end of input")
+ 
+-n_errors = 0
++
+ def error(msg):
+     global n_errors
+     sys.stderr.write("%s:%d: %s\n" % (file_name, line_number, msg))
+     n_errors += 1
+ 
++
+ def fatal(msg):
+     error(msg)
+     sys.exit(1)
+ 
++
+ def usage():
+     argv0 = os.path.basename(sys.argv[0])
+     print('''\
+@@ -65,6 +71,7 @@ only controls #line directives in the output.\
+ ''' % {"argv0": argv0})
+     sys.exit(0)
+ 
++
+ def make_sizeof(s):
+     m = re.match(r'(.*) up to (.*)', s)
+     if m:
+@@ -73,9 +80,8 @@ def make_sizeof(s):
+     else:
+         return "sizeof(%s)" % s
+ 
+-def extract_ofp_msgs(output_file_name):
+-    raw_types = []
+ 
++def extract_ofp_msgs(output_file_name):
+     all_hdrs = {}
+     all_raws = {}
+     all_raws_order = []
+@@ -108,15 +114,16 @@ def extract_ofp_msgs(output_file_name):
+             comment += ' %s' % line.lstrip('* \t').rstrip(' \t\r\n')
+         comment = comment[:-2].rstrip()
+ 
+-        m = re.match(r'([A-Z]+) ([-.+\d]+|<all>) \((\d+)\): ([^.]+)\.$', comment)
++        m = re.match(
++            r'([A-Z]+) ([-.+\d]+|<all>) \((\d+)\): ([^.]+)\.$', comment
++        )
+         if not m:
+             fatal("unexpected syntax between messages")
+         type_, versions, number, contents = m.groups()
+         number = int(number)
+ 
+         get_line()
+-        m = re.match('\s+(?:OFPRAW_%s)(\d*)_([A-Z0-9_]+),?$' % type_,
+-                     line)
++        m = re.match(r'\s+(?:OFPRAW_%s)(\d*)_([A-Z0-9_]+),?$' % type_, line)
+         if not m:
+             fatal("syntax error expecting OFPRAW_ enum")
+         vinfix, name = m.groups()
+@@ -300,7 +307,7 @@ def extract_ofp_msgs(output_file_name):
+         for hdrs in r['hdrs']:
+             output.append("    { {0, NULL}, {%d, %d, %d, 0x%x, %d}, %s, 0 },"
+                           % (hdrs + (raw,)))
+-                
++
+         output.append("};")
+ 
+     output.append("")
+@@ -349,8 +356,8 @@ def extract_ofp_msgs(output_file_name):
+                               % r["human_name"])
+     output.append("};")
+ 
+-    output.append("");
+-    output.append("static const char *type_names[] = {");
++    output.append("")
++    output.append("static const char *type_names[] = {")
+     for t in all_types:
+         output.append("    \"%s\"," % t)
+     output.append("};")
+@@ -378,4 +385,3 @@ if __name__ == '__main__':
+ 
+         for line in extract_ofp_msgs(sys.argv[2]):
+             print(line)
+-        
 diff --git a/build-aux/generate-dhparams-c b/build-aux/generate-dhparams-c
 index 1884c99e1f..aca1dbca91 100755
 --- a/build-aux/generate-dhparams-c
@@ -868,6 +1975,17 @@ index 4e9bcce272..3c9562a441 100644
  AM_PROG_CC_C_O
  AC_PROG_CXX
  AC_PROG_CPP
+diff --git a/datapath-windows/include/automake.mk b/datapath-windows/include/automake.mk
+index b8dcf83b90..66373907d7 100644
+--- a/datapath-windows/include/automake.mk
++++ b/datapath-windows/include/automake.mk
+@@ -7,6 +7,4 @@ $(srcdir)/datapath-windows/include/OvsDpInterface.h: \
+          build-aux/extract-odp-netlink-windows-dp-h
+ 	$(AM_V_GEN)sed -f $(srcdir)/build-aux/extract-odp-netlink-windows-dp-h < $< > $@
+ 
+-EXTRA_DIST += $(srcdir)/build-aux/extract-odp-netlink-windows-dp-h
+-
+ CLEANFILES += $(srcdir)/datapath-windows/include/OvsDpInterface.h
 diff --git a/datapath-windows/ovsext/Actions.c b/datapath-windows/ovsext/Actions.c
 index 70ac0a0e56..e3eb05d659 100644
 --- a/datapath-windows/ovsext/Actions.c
@@ -50395,6 +51513,18 @@ index 12cb6e0e83..21dc51f00d 100644
  dpdk_conf = configuration_data()
  dpdk_libraries = []
  dpdk_static_libraries = []
+diff --git a/include/automake.mk b/include/automake.mk
+index e982da87d7..c40519eeb1 100644
+--- a/include/automake.mk
++++ b/include/automake.mk
+@@ -8,7 +8,6 @@ include/odp-netlink-macros.h: include/odp-netlink.h \
+                               build-aux/extract-odp-netlink-macros-h
+ 	$(AM_V_GEN)sh -f $(srcdir)/build-aux/extract-odp-netlink-macros-h $< > $@
+ 
+-EXTRA_DIST += build-aux/extract-odp-netlink-h build-aux/extract-odp-netlink-macros-h
+ CLEANFILES += include/odp-netlink.h include/odp-netlink-macros.h
+ 
+ include include/openflow/automake.mk
 diff --git a/include/linux/automake.mk b/include/linux/automake.mk
 index 8f063f482e..f857c7e088 100644
 --- a/include/linux/automake.mk
@@ -50494,6 +51624,17 @@ index 0000000000..6fae6f727c
 +
 +#endif /* __KERNEL__ || !HAVE_TCA_STATS_PKT64 */
 +#endif /* __LINUX_GEN_STATS_WRAPPER_H */
+diff --git a/include/openflow/automake.mk b/include/openflow/automake.mk
+index a1d75756c9..820c09f84b 100644
+--- a/include/openflow/automake.mk
++++ b/include/openflow/automake.mk
+@@ -22,6 +22,3 @@ HSTAMP_FILES = $(openflowinclude_HEADERS:.h=.hstamp)
+ CLEANFILES += $(HSTAMP_FILES)
+ ALL_LOCAL += $(HSTAMP_FILES)
+ $(HSTAMP_FILES): build-aux/check-structs $(openflowinclude_HEADERS)
+-
+-EXTRA_DIST += build-aux/check-structs
+-
 diff --git a/include/openvswitch/compiler.h b/include/openvswitch/compiler.h
 index cf009f8264..52614a5ac0 100644
 --- a/include/openvswitch/compiler.h
@@ -51188,7 +52329,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..3c4a58ed9c 100644
+index a23cdc4ade..087656729a 100644
 --- a/lib/automake.mk
 +++ b/lib/automake.mk
 @@ -38,8 +38,6 @@ lib_libopenvswitchavx512_la_CFLAGS = \
@@ -51218,6 +52359,37 @@ index a23cdc4ade..3c4a58ed9c 100644
  if HAVE_WNO_UNUSED
  lib_libsflow_la_CFLAGS += -Wno-unused
  endif
+@@ -627,7 +627,6 @@ lib/nx-match.inc: $(srcdir)/build-aux/extract-ofp-fields include/openvswitch/met
+ 	$(AM_V_at)mv $@.tmp $@
+ lib/nx-match.lo: lib/nx-match.inc
+ CLEANFILES += lib/meta-flow.inc lib/nx-match.inc
+-EXTRA_DIST += build-aux/extract-ofp-fields
+ 
+ lib/ofp-actions.inc1: $(srcdir)/build-aux/extract-ofp-actions lib/ofp-actions.c
+ 	$(AM_V_GEN)$(run_python) $< prototypes $(srcdir)/lib/ofp-actions.c > $@.tmp && mv $@.tmp $@
+@@ -635,7 +634,6 @@ lib/ofp-actions.inc2: $(srcdir)/build-aux/extract-ofp-actions lib/ofp-actions.c
+ 	$(AM_V_GEN)$(run_python) $< definitions $(srcdir)/lib/ofp-actions.c > $@.tmp && mv $@.tmp $@
+ lib/ofp-actions.lo: lib/ofp-actions.inc1 lib/ofp-actions.inc2
+ CLEANFILES += lib/ofp-actions.inc1 lib/ofp-actions.inc2
+-EXTRA_DIST += build-aux/extract-ofp-actions
+ 
+ lib/ofp-errors.inc: include/openvswitch/ofp-errors.h include/openflow/openflow-common.h \
+ 	$(srcdir)/build-aux/extract-ofp-errors
+@@ -645,14 +643,12 @@ lib/ofp-errors.inc: include/openvswitch/ofp-errors.h include/openflow/openflow-c
+ 	mv $@.tmp $@
+ lib/ofp-errors.lo: lib/ofp-errors.inc
+ CLEANFILES += lib/ofp-errors.inc
+-EXTRA_DIST += build-aux/extract-ofp-errors
+ 
+ lib/ofp-msgs.inc: include/openvswitch/ofp-msgs.h $(srcdir)/build-aux/extract-ofp-msgs
+ 	$(AM_V_GEN)$(run_python) $(srcdir)/build-aux/extract-ofp-msgs \
+ 		$(srcdir)/include/openvswitch/ofp-msgs.h $@ > $@.tmp && mv $@.tmp $@
+ lib/ofp-msgs.lo: lib/ofp-msgs.inc
+ CLEANFILES += lib/ofp-msgs.inc
+-EXTRA_DIST += build-aux/extract-ofp-msgs
+ 
+ # _server IDL
+ OVSIDL_BUILT += lib/ovsdb-server-idl.c lib/ovsdb-server-idl.h lib/ovsdb-server-idl.ovsidl
 diff --git a/lib/cfm.c b/lib/cfm.c
 index cc43e70e31..c3742f3de2 100644
 --- a/lib/cfm.c
@@ -66844,6 +68016,19 @@ index 4ecdcaa197..1aa0c33d13 100644
              except error.Error:
                  return
              if key not in old_value:
+diff --git a/python/ovs/jsonrpc.py b/python/ovs/jsonrpc.py
+index d5127268aa..d9fe27aec6 100644
+--- a/python/ovs/jsonrpc.py
++++ b/python/ovs/jsonrpc.py
+@@ -377,7 +377,7 @@ class Session(object):
+         self.stream = None
+         self.pstream = None
+         self.seqno = 0
+-        if type(remotes) != list:
++        if type(remotes) is not list:
+             remotes = [remotes]
+         self.remotes = remotes
+         random.shuffle(self.remotes)
 diff --git a/python/ovs/reconnect.py b/python/ovs/reconnect.py
 index c4c6c87e9f..6b0d023ae3 100644
 --- a/python/ovs/reconnect.py
@@ -75206,6 +76391,26 @@ index 072a537252..fa51bb31c5 100644
      }
  
      fclose(stream);
+diff --git a/tests/test-jsonrpc.py b/tests/test-jsonrpc.py
+index 1df5afa221..8a4a175938 100644
+--- a/tests/test-jsonrpc.py
++++ b/tests/test-jsonrpc.py
+@@ -199,13 +199,13 @@ notify REMOTE METHOD PARAMS  send notification and exit
+         sys.exit(1)
+ 
+     func, n_args = commands[command_name]
+-    if type(n_args) == tuple:
++    if type(n_args) is tuple:
+         if len(args) < n_args[0]:
+             sys.stderr.write("%s: \"%s\" requires at least %d arguments but "
+                              "only %d provided\n"
+                              % (argv[0], command_name, n_args, len(args)))
+             sys.exit(1)
+-    elif type(n_args) == int:
++    elif type(n_args) is int:
+         if len(args) != n_args:
+             sys.stderr.write("%s: \"%s\" requires %d arguments but %d "
+                              "provided\n"
 diff --git a/tests/test-list.c b/tests/test-list.c
 index 6f1fb059bc..ac82f2048e 100644
 --- a/tests/test-list.c
@@ -75736,9 +76941,43 @@ index ca4e87b811..cd1c31a6c2 100644
              idl_set(idl, arg, step++);
          } else {
 diff --git a/tests/test-ovsdb.py b/tests/test-ovsdb.py
-index 853264f22b..eded9140e4 100644
+index 853264f22b..3c76835d4b 100644
 --- a/tests/test-ovsdb.py
 +++ b/tests/test-ovsdb.py
+@@ -37,7 +37,7 @@ vlog.init(None)
+ 
+ 
+ def unbox_json(json):
+-    if type(json) == list and len(json) == 1:
++    if type(json) is list and len(json) == 1:
+         return json[0]
+     else:
+         return json
+@@ -325,9 +325,9 @@ def substitute_uuids(json, symtab):
+         symbol = symtab.get(json)
+         if symbol:
+             return str(symbol)
+-    elif type(json) == list:
++    elif type(json) is list:
+         return [substitute_uuids(element, symtab) for element in json]
+-    elif type(json) == dict:
++    elif type(json) is dict:
+         d = {}
+         for key, value in json.items():
+             d[key] = substitute_uuids(value, symtab)
+@@ -341,10 +341,10 @@ def parse_uuids(json, symtab):
+         name = "#%d#" % len(symtab)
+         sys.stderr.write("%s = %s\n" % (name, json))
+         symtab[name] = json
+-    elif type(json) == list:
++    elif type(json) is list:
+         for element in json:
+             parse_uuids(element, symtab)
+-    elif type(json) == dict:
++    elif type(json) is dict:
+         for value in json.values():
+             parse_uuids(value, symtab)
+ 
 @@ -616,18 +616,32 @@ def idl_set(idl, commands, step):
      sys.stdout.flush()
  
@@ -75822,6 +77061,23 @@ index 853264f22b..eded9140e4 100644
              step += 1
          elif not command.startswith("["):
              idl_set(idl, command, step)
+@@ -1012,14 +1033,14 @@ def main(argv):
+         sys.exit(1)
+ 
+     func, n_args = commands[command_name]
+-    if type(n_args) == tuple:
++    if type(n_args) is tuple:
+         if len(args) < n_args[0]:
+             sys.stderr.write("%s: \"%s\" requires at least %d arguments but "
+                              "only %d provided\n"
+                              % (ovs.util.PROGRAM_NAME, command_name,
+                                 n_args[0], len(args)))
+             sys.exit(1)
+-    elif type(n_args) == int:
++    elif type(n_args) is int:
+         if len(args) != n_args:
+             sys.stderr.write("%s: \"%s\" requires %d arguments but %d "
+                              "provided\n"
 diff --git a/tests/test-rcu.c b/tests/test-rcu.c
 index 965f3c49f3..bb17092bf0 100644
 --- a/tests/test-rcu.c
diff --git a/SPECS/openvswitch2.17.spec b/SPECS/openvswitch2.17.spec
index 0f9dbd7..66705de 100644
--- a/SPECS/openvswitch2.17.spec
+++ b/SPECS/openvswitch2.17.spec
@@ -63,7 +63,7 @@ Summary: Open vSwitch
 Group: System Environment/Daemons daemon/database/utilities
 URL: http://www.openvswitch.org/
 Version: 2.17.0
-Release: 135%{?dist}
+Release: 136%{?dist}
 
 # Nearly all of openvswitch is ASL 2.0.  The bugtool is LGPLv2+, and the
 # lib/sflow*.[ch] files are SISSL
@@ -749,6 +749,18 @@ exit 0
 %endif
 
 %changelog
+* Wed Nov 01 2023 Open vSwitch CI <ovs-ci@redhat.com> - 2.17.0-136
+- Merging upstream branch-2.17 [RH git: 83fa49d2bf]
+    Commit list:
+    8313ebbb33 flake8: Fix E721 check failures.
+    f73208151a build-aux: Enable flake8 checks for python extraction scripts.
+    8b6a8fcb0a build-aux/extract-ofp-msgs: Fix flake8 and syntax errors.
+    80e922644f build-aux/extract-ofp-fields: Fix flake8 and syntax errors.
+    1508e7abce build-aux/extract-ofp-errors: Fix flake8 and syntax errors.
+    98fc48e4dc build-aux/extract-ofp-actions: Fix flake8 and syntax errors.
+    d52231171e automake: Move build-aux EXTRA_DIST updates to their own file.
+
+
 * Tue Oct 31 2023 Open vSwitch CI <ovs-ci@redhat.com> - 2.17.0-135
 - Merging upstream branch-2.17 [RH git: b6b48e1eb4]
     Commit list: