diff --git a/SOURCES/openvswitch-2.16.0.patch b/SOURCES/openvswitch-2.16.0.patch
index bb19a71..3eecc53 100644
--- a/SOURCES/openvswitch-2.16.0.patch
+++ b/SOURCES/openvswitch-2.16.0.patch
@@ -1,20 +1,22 @@
 diff --git a/.ci/linux-prepare.sh b/.ci/linux-prepare.sh
-index c55125cf78..e4d2a187e0 100755
+index c55125cf78..360c0a68ea 100755
 --- a/.ci/linux-prepare.sh
 +++ b/.ci/linux-prepare.sh
-@@ -22,7 +22,6 @@ cd ..
+@@ -21,8 +21,7 @@ make -j4 HAVE_LLVM= HAVE_SQLITE= install
+ cd ..
  
  pip3 install --disable-pip-version-check --user \
-     flake8 hacking sphinx pyOpenSSL wheel setuptools
+-    flake8 hacking sphinx pyOpenSSL wheel setuptools
 -pip3 install --user --upgrade docutils
++    flake8 hacking sphinx wheel setuptools
  pip3 install --user  'meson==0.47.1'
  
  if [ "$M32" ]; then
 diff --git a/.cirrus.yml b/.cirrus.yml
-index 358f2ba256..480fea2421 100644
+index 358f2ba256..a7ae793bc4 100644
 --- a/.cirrus.yml
 +++ b/.cirrus.yml
-@@ -5,7 +5,7 @@ freebsd_build_task:
+@@ -5,11 +5,11 @@ freebsd_build_task:
        image_family: freebsd-12-2-snap
        image_family: freebsd-11-4-snap
      cpu: 4
@@ -23,6 +25,11 @@ index 358f2ba256..480fea2421 100644
  
    env:
      DEPENDENCIES: automake libtool gmake gcc wget openssl python3
+-    PY_DEPS:      sphinx|openssl
++    PY_DEPS:      sphinx
+     matrix:
+       COMPILER: gcc
+       COMPILER: clang
 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
 index e2350c6d9d..7434ad18ec 100644
 --- a/.github/workflows/build-and-test.yml
@@ -45,13 +52,28 @@ index e2350c6d9d..7434ad18ec 100644
      - name: install dependencies
        run:  brew install automake libtool
      - name: prepare
+diff --git a/.travis.yml b/.travis.yml
+index 51d0511080..c7aeede06e 100644
+--- a/.travis.yml
++++ b/.travis.yml
+@@ -17,7 +17,6 @@ addons:
+       - libjemalloc-dev
+       - libnuma-dev
+       - libpcap-dev
+-      - python3-openssl
+       - python3-pip
+       - python3-sphinx
+       - libelf-dev
 diff --git a/NEWS b/NEWS
-index 559a51ba3f..7a6de3da82 100644
+index 559a51ba3f..139c24a4f8 100644
 --- a/NEWS
 +++ b/NEWS
-@@ -1,3 +1,10 @@
+@@ -1,3 +1,13 @@
 +v2.16.2 - xx xxx xxxx
 +---------------------
++   - Python:
++     * For SSL support, the use of the pyOpenSSL library has been replaced
++       with the native 'ssl' module.
 +
 +v2.16.1 - 21 Oct 2021
 +---------------------
@@ -3720,6 +3742,271 @@ index 626ae8fc44..3318a3b6f8 100644
          else:
              return "%(dst)s = %(src)s;" % args
  
+diff --git a/python/ovs/poller.py b/python/ovs/poller.py
+index 3624ec8655..157719c3a4 100644
+--- a/python/ovs/poller.py
++++ b/python/ovs/poller.py
+@@ -26,9 +26,9 @@ if sys.platform == "win32":
+     import ovs.winutils as winutils
+ 
+ try:
+-    from OpenSSL import SSL
++    import ssl
+ except ImportError:
+-    SSL = None
++    ssl = None
+ 
+ try:
+     from eventlet import patcher as eventlet_patcher
+@@ -73,7 +73,7 @@ class _SelectSelect(object):
+     def register(self, fd, events):
+         if isinstance(fd, socket.socket):
+             fd = fd.fileno()
+-        if SSL and isinstance(fd, SSL.Connection):
++        if ssl and isinstance(fd, ssl.SSLSocket):
+             fd = fd.fileno()
+ 
+         if sys.platform != 'win32':
+diff --git a/python/ovs/socket_util.py b/python/ovs/socket_util.py
+index 3faa64e9d7..651012bf06 100644
+--- a/python/ovs/socket_util.py
++++ b/python/ovs/socket_util.py
+@@ -222,8 +222,7 @@ def inet_parse_active(target, default_port):
+     return (host_name, port)
+ 
+ 
+-def inet_open_active(style, target, default_port, dscp):
+-    address = inet_parse_active(target, default_port)
++def inet_create_socket_active(style, address):
+     try:
+         is_addr_inet = is_valid_ipv4_address(address[0])
+         if is_addr_inet:
+@@ -235,23 +234,32 @@ def inet_open_active(style, target, default_port, dscp):
+     except socket.error as e:
+         return get_exception_errno(e), None
+ 
++    return family, sock
++
++
++def inet_connect_active(sock, address, family, dscp):
+     try:
+         set_nonblocking(sock)
+         set_dscp(sock, family, dscp)
+-        try:
+-            sock.connect(address)
+-        except socket.error as e:
+-            error = get_exception_errno(e)
+-            if sys.platform == 'win32' and error == errno.WSAEWOULDBLOCK:
+-                # WSAEWOULDBLOCK would be the equivalent on Windows
+-                # for EINPROGRESS on Unix.
+-                error = errno.EINPROGRESS
+-            if error != errno.EINPROGRESS:
+-                raise
+-        return 0, sock
++        error = sock.connect_ex(address)
++        if error not in (0, errno.EINPROGRESS, errno.EWOULDBLOCK):
++            sock.close()
++            return error
++        return 0
+     except socket.error as e:
+         sock.close()
+-        return get_exception_errno(e), None
++        return get_exception_errno(e)
++
++
++def inet_open_active(style, target, default_port, dscp):
++    address = inet_parse_active(target, default_port)
++    family, sock = inet_create_socket_active(style, address)
++    if sock is None:
++        return family, sock
++    error = inet_connect_active(sock, address, family, dscp)
++    if error:
++        return error, None
++    return 0, sock
+ 
+ 
+ def get_exception_errno(e):
+diff --git a/python/ovs/stream.py b/python/ovs/stream.py
+index f5a520862c..ac5b0fd0c6 100644
+--- a/python/ovs/stream.py
++++ b/python/ovs/stream.py
+@@ -22,9 +22,9 @@ import ovs.socket_util
+ import ovs.vlog
+ 
+ try:
+-    from OpenSSL import SSL
++    import ssl
+ except ImportError:
+-    SSL = None
++    ssl = None
+ 
+ if sys.platform == 'win32':
+     import ovs.winutils as winutils
+@@ -322,6 +322,12 @@ class Stream(object):
+         The recv function will not block waiting for data to arrive.  If no
+         data have been received, it returns (errno.EAGAIN, "") immediately."""
+ 
++        try:
++            return self._recv(n)
++        except socket.error as e:
++            return (ovs.socket_util.get_exception_errno(e), "")
++
++    def _recv(self, n):
+         retval = self.connect()
+         if retval != 0:
+             return (retval, "")
+@@ -331,10 +337,7 @@ class Stream(object):
+         if sys.platform == 'win32' and self.socket is None:
+             return self.__recv_windows(n)
+ 
+-        try:
+-            return (0, self.socket.recv(n))
+-        except socket.error as e:
+-            return (ovs.socket_util.get_exception_errno(e), "")
++        return (0, self.socket.recv(n))
+ 
+     def __recv_windows(self, n):
+         if self._read_pending:
+@@ -396,6 +399,12 @@ class Stream(object):
+         Will not block.  If no bytes can be immediately accepted for
+         transmission, returns -errno.EAGAIN immediately."""
+ 
++        try:
++            return self._send(buf)
++        except socket.error as e:
++            return -ovs.socket_util.get_exception_errno(e)
++
++    def _send(self, buf):
+         retval = self.connect()
+         if retval != 0:
+             return -retval
+@@ -409,10 +418,7 @@ class Stream(object):
+         if sys.platform == 'win32' and self.socket is None:
+             return self.__send_windows(buf)
+ 
+-        try:
+-            return self.socket.send(buf)
+-        except socket.error as e:
+-            return -ovs.socket_util.get_exception_errno(e)
++        return self.socket.send(buf)
+ 
+     def __send_windows(self, buf):
+         if self._write_pending:
+@@ -769,35 +775,42 @@ class SSLStream(Stream):
+     def check_connection_completion(sock):
+         try:
+             return Stream.check_connection_completion(sock)
+-        except SSL.SysCallError as e:
++        except ssl.SSLSyscallError as e:
+             return ovs.socket_util.get_exception_errno(e)
+ 
+     @staticmethod
+     def needs_probes():
+         return True
+ 
+-    @staticmethod
+-    def verify_cb(conn, cert, errnum, depth, ok):
+-        return ok
+-
+     @staticmethod
+     def _open(suffix, dscp):
+-        error, sock = TCPStream._open(suffix, dscp)
+-        if error:
+-            return error, None
++        address = ovs.socket_util.inet_parse_active(suffix, 0)
++        family, sock = ovs.socket_util.inet_create_socket_active(
++                socket.SOCK_STREAM, address)
++        if sock is None:
++            return family, sock
+ 
+         # Create an SSL context
+-        ctx = SSL.Context(SSL.SSLv23_METHOD)
+-        ctx.set_verify(SSL.VERIFY_PEER, SSLStream.verify_cb)
+-        ctx.set_options(SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3)
++        ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
++        ctx.verify_mode = ssl.CERT_REQUIRED
++        ctx.options |= ssl.OP_NO_SSLv2
++        ctx.options |= ssl.OP_NO_SSLv3
+         # If the client has not set the SSL configuration files
+         # exception would be raised.
+-        ctx.use_privatekey_file(Stream._SSL_private_key_file)
+-        ctx.use_certificate_file(Stream._SSL_certificate_file)
+         ctx.load_verify_locations(Stream._SSL_ca_cert_file)
++        ctx.load_cert_chain(Stream._SSL_certificate_file,
++                            Stream._SSL_private_key_file)
++        ssl_sock = ctx.wrap_socket(sock, do_handshake_on_connect=False)
+ 
+-        ssl_sock = SSL.Connection(ctx, sock)
+-        ssl_sock.set_connect_state()
++        # Connect
++        error = ovs.socket_util.inet_connect_active(ssl_sock, address, family,
++                                                    dscp)
++        if not error:
++            try:
++                ssl_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
++            except socket.error as e:
++                ssl_sock.close()
++                return ovs.socket_util.get_exception_errno(e), None
+         return error, ssl_sock
+ 
+     def connect(self):
+@@ -809,40 +822,44 @@ class SSLStream(Stream):
+         # TCP Connection is successful. Now do the SSL handshake
+         try:
+             self.socket.do_handshake()
+-        except SSL.WantReadError:
++        except ssl.SSLWantReadError:
+             return errno.EAGAIN
+-        except SSL.SysCallError as e:
++        except ssl.SSLSyscallError as e:
+             return ovs.socket_util.get_exception_errno(e)
+ 
+         return 0
+ 
+     def recv(self, n):
+         try:
+-            return super(SSLStream, self).recv(n)
+-        except SSL.WantReadError:
++            return super(SSLStream, self)._recv(n)
++        except ssl.SSLWantReadError:
+             return (errno.EAGAIN, "")
+-        except SSL.SysCallError as e:
++        except ssl.SSLSyscallError as e:
+             return (ovs.socket_util.get_exception_errno(e), "")
+-        except SSL.ZeroReturnError:
++        except ssl.SSLZeroReturnError:
+             return (0, "")
++        except socket.error as e:
++            return (ovs.socket_util.get_exception_errno(e), "")
+ 
+     def send(self, buf):
+         try:
+-            return super(SSLStream, self).send(buf)
+-        except SSL.WantWriteError:
++            return super(SSLStream, self)._send(buf)
++        except ssl.SSLWantWriteError:
+             return -errno.EAGAIN
+-        except SSL.SysCallError as e:
++        except ssl.SSLSyscallError as e:
++            return -ovs.socket_util.get_exception_errno(e)
++        except socket.error as e:
+             return -ovs.socket_util.get_exception_errno(e)
+ 
+     def close(self):
+         if self.socket:
+             try:
+-                self.socket.shutdown()
+-            except SSL.Error:
++                self.socket.shutdown(socket.SHUT_RDWR)
++            except socket.error:
+                 pass
+         return super(SSLStream, self).close()
+ 
+ 
+-if SSL:
++if ssl:
+     # Register SSL only if the OpenSSL module is available
+     Stream.register_method("ssl", SSLStream)
 diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
 index 956a69e1fa..1dad6f62c6 100644
 --- a/tests/ofproto-dpif.at
@@ -3821,6 +4108,19 @@ index 8cd2a26cb3..25c6acdac6 100644
  OK]])
  
  OVSDB_CHECK_NEGATIVE([generate and apply diff with map -- size error],
+diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at
+index 1386f13770..cd28a587c6 100644
+--- a/tests/ovsdb-idl.at
++++ b/tests/ovsdb-idl.at
+@@ -225,7 +225,7 @@ m4_define([OVSDB_CHECK_IDL_TCP6_MULTIPLE_REMOTES_PY],
+ m4_define([OVSDB_CHECK_IDL_SSL_PY],
+   [AT_SETUP([$1 - Python3 - SSL])
+    AT_SKIP_IF([test "$HAVE_OPENSSL" = no])
+-   $PYTHON3 -c "import OpenSSL.SSL"
++   $PYTHON3 -c "import ssl"
+    SSL_PRESENT=$?
+    AT_SKIP_IF([test $SSL_PRESENT != 0])
+    AT_KEYWORDS([ovsdb server idl positive Python with ssl socket $5])
 diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at
 index ac243d6a79..2b742f78b0 100644
 --- a/tests/ovsdb-server.at
diff --git a/SPECS/openvswitch2.16.spec b/SPECS/openvswitch2.16.spec
index 33af697..2bc08fb 100644
--- a/SPECS/openvswitch2.16.spec
+++ b/SPECS/openvswitch2.16.spec
@@ -57,7 +57,7 @@ Summary: Open vSwitch
 Group: System Environment/Daemons daemon/database/utilities
 URL: http://www.openvswitch.org/
 Version: 2.16.0
-Release: 28%{?dist}
+Release: 30%{?dist}
 
 # Nearly all of openvswitch is ASL 2.0.  The bugtool is LGPLv2+, and the
 # lib/sflow*.[ch] files are SISSL
@@ -699,6 +699,60 @@ exit 0
 %endif
 
 %changelog
+* Wed Nov 10 2021 Timothy Redaelli <tredaelli@redhat.com> - 2.16.0-30
+- python: Replace pyOpenSSL with ssl. [RH git: 0cd5867531] (#1988429)
+    Currently, pyOpenSSL is half-deprecated upstream and so it's removed on
+    some distributions (for example on CentOS Stream 9,
+    https://issues.redhat.com/browse/CS-336), but since OVS only
+    supports Python 3 it's possible to replace pyOpenSSL with "import ssl"
+    included in base Python 3.
+    
+    Stream recv and send had to be splitted as _recv and _send, since SSLError
+    is a subclass of socket.error and so it was not possible to except for
+    SSLWantReadError and SSLWantWriteError in recv and send of SSLStream.
+    
+    TCPstream._open cannot be used in SSLStream, since Python ssl module
+    requires the SSL socket to be created before connecting it, so
+    SSLStream._open needs to create the socket, create SSL socket and then
+    connect the SSL socket.
+    
+    Reported-by: Timothy Redaelli <tredaelli@redhat.com>
+    Reported-at: https://bugzilla.redhat.com/1988429
+    Signed-off-by: Timothy Redaelli <tredaelli@redhat.com>
+    Acked-by: Terry Wilson <twilson@redhat.com>
+    Tested-by: Terry Wilson <twilson@redhat.com>
+    Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+    Signed-off-by: Timothy Redaelli <tredaelli@redhat.com>
+
+
+* Wed Nov 10 2021 Timothy Redaelli <tredaelli@redhat.com> - 2.16.0-29
+- python: socket-util: Split inet_open_active function and use connect_ex. [RH git: 2e704b371c]
+    In an upcoming patch, PyOpenSSL will be replaced with Python ssl module,
+    but in order to do an async connection with Python ssl module the ssl
+    socket must be created when the socket is created, but before the
+    socket is connected.
+    
+    So, inet_open_active function is splitted in 3 parts:
+    - inet_create_socket_active: creates the socket and returns the family and
+      the socket, or (error, None) if some error needs to be returned.
+    - inet_connect_active: connect the socket and returns the errno (it
+      returns 0 if errno is EINPROGRESS or EWOULDBLOCK).
+    
+    connect is replaced by connect_ex, since Python suggest to use it for
+    asynchronous connects and it's also cleaner since inet_connect_active
+    returns errno that connect_ex already returns, moreover due to a Python
+    limitation connect cannot not be used with ssl module.
+    
+    inet_open_active function is changed in order to use the new functions
+    inet_create_socket_active and inet_connect_active.
+    
+    Signed-off-by: Timothy Redaelli <tredaelli@redhat.com>
+    Acked-by: Terry Wilson <twilson@redhat.com>
+    Tested-by: Terry Wilson <twilson@redhat.com>
+    Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
+    Signed-off-by: Timothy Redaelli <tredaelli@redhat.com>
+
+
 * Wed Nov 10 2021 Timothy Redaelli <tredaelli@redhat.com> - 2.16.0-28
 - redhat: remove mlx4 support [RH git: 4c846afd24] (#1998122)
     Resolves: #1998122