[ovs-dev] [PATCH] python: Add SSL support to the python ovs client library
From: Numan Siddique SSL support is added to the ovs/stream.py. pyOpenSSL library is used to support SSL. If this library is not present, then the SSL stream is not registered with the Stream class. Signed-off-by: Numan Siddique --- python/ovs/poller.py | 8 + python/ovs/stream.py | 87 ++-- tests/ovsdb-idl.at | 30 -- tests/test-ovsdb.py | 7 + 4 files changed, 127 insertions(+), 5 deletions(-) diff --git a/python/ovs/poller.py b/python/ovs/poller.py index de6bf22..d7cb7d3 100644 --- a/python/ovs/poller.py +++ b/python/ovs/poller.py @@ -20,6 +20,11 @@ import socket import os try: +from OpenSSL import SSL +except ImportError: +SSL = None + +try: import eventlet.patcher def _using_eventlet_green_select(): @@ -54,6 +59,9 @@ class _SelectSelect(object): def register(self, fd, events): if isinstance(fd, socket.socket): fd = fd.fileno() +if SSL and isinstance(fd, SSL.Connection): +fd = fd.fileno() + assert isinstance(fd, int) if events & POLLIN: self.rlist.append(fd) diff --git a/python/ovs/stream.py b/python/ovs/stream.py index 97b22ac..bb813a6 100644 --- a/python/ovs/stream.py +++ b/python/ovs/stream.py @@ -22,6 +22,11 @@ import ovs.poller import ovs.socket_util import ovs.vlog +try: +from OpenSSL import SSL +except ImportError: +SSL = None + vlog = ovs.vlog.Vlog("stream") @@ -39,7 +44,7 @@ def stream_or_pstream_needs_probes(name): class Stream(object): -"""Bidirectional byte stream. Currently only Unix domain sockets +"""Bidirectional byte stream. Unix domain sockets, tcp and ssl are implemented.""" # States. @@ -54,6 +59,10 @@ class Stream(object): _SOCKET_METHODS = {} +_SSL_private_key_file = None +_SSL_certificate_file = None +_SSL_ca_cert_file = None + @staticmethod def register_method(method, cls): Stream._SOCKET_METHODS[method + ":"] = cls @@ -68,7 +77,7 @@ class Stream(object): @staticmethod def is_valid_name(name): """Returns True if 'name' is a stream name in the form "TYPE:ARGS" and -TYPE is a supported stream type (currently only "unix:" and "tcp:"), +TYPE is a supported stream type ("unix:", "tcp:" and "ssl:"), otherwise False.""" return bool(Stream._find_method(name)) @@ -116,7 +125,7 @@ class Stream(object): return error, None else: status = ovs.socket_util.check_connection_completion(sock) -return 0, Stream(sock, name, status) +return 0, cls(sock, name, status) @staticmethod def _open(suffix, dscp): @@ -264,6 +273,18 @@ class Stream(object): # Don't delete the file: we might have forked. self.socket.close() +@staticmethod +def ssl_set_private_key_file(file_name): +Stream._SSL_private_key_file = file_name + +@staticmethod +def ssl_set_certificate_file(file_name): +Stream._SSL_certificate_file = file_name + +@staticmethod +def ssl_set_ca_cert_file(file_name): +Stream._SSL_ca_cert_file = file_name + class PassiveStream(object): @staticmethod @@ -362,6 +383,7 @@ def usage(name): Active %s connection methods: unix:FILE Unix domain socket named FILE tcp:IP:PORT TCP socket to IP with port no of PORT + ssl:IP:PORT SSL socket to IP with port no of PORT Passive %s connection methods: punix:FILE Listen on Unix domain socket FILE""" % (name, name) @@ -385,3 +407,62 @@ class TCPStream(Stream): sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) return error, sock Stream.register_method("tcp", TCPStream) + + +class SSLStream(Stream): + +@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 + +# 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.set_session_cache_mode(SSL.SESS_CACHE_OFF) +# 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) + +ssl_sock = SSL.Connection(ctx, sock) +ssl_sock.set_connect_state() +return error, ssl_sock + +def connect(self): +retval = super(SSLStream, self).connect() + +if retval: +return retval + +# TCP Connection is successful. Now do the SSL handshake +try: +self.
[ovs-dev] [PATCH v3 4/4] ovn: Add tests for ovn dhcp
Signed-off-by: Numan Siddique --- tests/automake.mk | 1 + tests/ovn.at | 184 +++ tests/test-ovn-dhcp.c | 211 ++ 3 files changed, 396 insertions(+) create mode 100644 tests/test-ovn-dhcp.c diff --git a/tests/automake.mk b/tests/automake.mk index 5267be1..9c19b1e 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -305,6 +305,7 @@ tests_ovstest_SOURCES = \ tests/test-odp.c \ tests/test-ofpbuf.c \ tests/test-ovn.c \ + tests/test-ovn-dhcp.c \ tests/test-packets.c \ tests/test-random.c \ tests/test-reconnect.c \ diff --git a/tests/ovn.at b/tests/ovn.at index 68fcc9a..34b9913 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -1104,3 +1104,187 @@ for i in 1 2 3; do done done AT_CLEANUP + +AT_SETUP([ovn dhcp -- 3 HVs, 3 LS, 3 lports/LS, 1 LR]) +AT_SKIP_IF([test $HAVE_PYTHON = no]) +ovn_start + +# Logical network: +# +# Three logical switches ls1, ls2, ls3. +# One logical router lr0 connected to ls[123], +# with nine subnets, three per logical switch: +# +#lrp11 on ls1 for subnet 192.168.11.0/24 +#lrp12 on ls1 for subnet 192.168.12.0/24 +#lrp13 on ls1 for subnet 192.168.13.0/24 +#... +#lrp33 on ls3 for subnet 192.168.33.0/24 +# +# 27 VIFs, 9 per LS, 3 per subnet: lp[123][123][123], where the first two +# digits are the subnet and the last digit distinguishes the VIF. +for i in 1 2 3; do +ovn-nbctl lswitch-add ls$i +for j in 1 2 3; do +for k in 1 2 3; do +ovn-nbctl \ +-- lport-add ls$i lp$i$j$k \ +-- lport-set-addresses lp$i$j$k "f0:00:00:00:0$i:$j$k 192.168.$i$j.$k" +done +done +done + +# Physical network: +# +# Three hypervisors hv[123]. +# lp?1[123] spread across hv[123]: lp?11 on hv1, lp?12 on hv2, lp?13 on hv3. +# lp?2[123] spread across hv[23]: lp?21 and lp?22 on hv2, lp?23 on hv3. +# lp?3[123] all on hv3. + + +# Given the name of a logical port, prints the name of the hypervisor +# on which it is located. +vif_to_hv() { +case $1 in dnl ( +?11) echo 1 ;; dnl ( +?12 | ?21 | ?22) echo 2 ;; dnl ( +?13 | ?23 | ?3?) echo 3 ;; +esac +} + +# Given the name of a logical port, prints the name of its logical router +# port, e.g. "vif_to_lrp 123" yields 12. +vif_to_lrp() { +echo ${1%?} +} + +# Given the name of a logical port, prints the name of its logical +# switch, e.g. "vif_to_ls 123" yields 1. +vif_to_ls() { +echo ${1%??} +} + +net_add n1 +for i in 1 2 3; do +sim_add hv$i +as hv$i +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.$i +done +for i in 1 2 3; do +for j in 1 2 3; do +for k in 1 2 3; do +hv=`vif_to_hv $i$j$k` +as hv$hv ovs-vsctl \ +-- add-port br-int vif$i$j$k \ +-- set Interface vif$i$j$k \ + external-ids:iface-id=lp$i$j$k \ + options:tx_pcap=hv$hv/vif$i$j$k-tx.pcap \ + options:rxq_pcap=hv$hv/vif$i$j$k-rx.pcap \ + ofport-request=$i$j$k +done +done +done + +# Pre-populate the hypervisors' ARP tables so that we don't lose any +# packets for ARP resolution (native tunneling doesn't queue packets +# for ARP resolution). +ovn_populate_arp + +# Allow some time for ovn-northd and ovn-controller to catch up. +# XXX This should be more systematic. +sleep 1 + +send_dhcp_packet() { +local inport=$1 src_mac=$2 dhcp_type=$3 +local request=${src_mac}0800451001108011 +# udp header and dhcp header +request+=0044004300FC +request+=010106006359aa76${src_mac} +# client hardware padding +request+= +# server hostname +request+= +request+= +# boot file name +request+= +request+= +request+= +request+= +# dhcp magic cookie +request+=63825363 +# dhcp message type +request+=3501${dhcp_type}ff +shift; shift; shift; shift; shift +hv=`vif_to_hv $inport` +as hv$hv ovs-appctl netdev-dummy/receive vif$inport $request +} + +ip_to_hex() { +printf "%02x%02x%02x%02x" "$@" +} + +run_dhcp_test() { +local i=$1 j=$2 k=$3 set_option=$4 dhcp_type=$5 +netmask=255.255.255.0 +gw_ip=0.0.0.0 +if $set_option = 'true'; then +netmask=255.255.252.0 +gw_ip=192.168.$i$j.254 +ovn-nbctl \ +-- lport-set-options lp$i$j$k \ +"dhcp-opt-1=$netmask" "dhcp-opt-3=$gw_ip" +sleep 1 +fi + +echo $gw_ip +
[ovs-dev] [PATCH v4 4/4] ovn: Add tests for ovn dhcp
Signed-off-by: Numan Siddique --- tests/automake.mk | 1 + tests/ovn.at | 184 tests/test-ovn-dhcp.c | 228 ++ 3 files changed, 413 insertions(+) create mode 100644 tests/test-ovn-dhcp.c diff --git a/tests/automake.mk b/tests/automake.mk index 5267be1..9c19b1e 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -305,6 +305,7 @@ tests_ovstest_SOURCES = \ tests/test-odp.c \ tests/test-ofpbuf.c \ tests/test-ovn.c \ + tests/test-ovn-dhcp.c \ tests/test-packets.c \ tests/test-random.c \ tests/test-reconnect.c \ diff --git a/tests/ovn.at b/tests/ovn.at index 68fcc9a..34b9913 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -1104,3 +1104,187 @@ for i in 1 2 3; do done done AT_CLEANUP + +AT_SETUP([ovn dhcp -- 3 HVs, 3 LS, 3 lports/LS, 1 LR]) +AT_SKIP_IF([test $HAVE_PYTHON = no]) +ovn_start + +# Logical network: +# +# Three logical switches ls1, ls2, ls3. +# One logical router lr0 connected to ls[123], +# with nine subnets, three per logical switch: +# +#lrp11 on ls1 for subnet 192.168.11.0/24 +#lrp12 on ls1 for subnet 192.168.12.0/24 +#lrp13 on ls1 for subnet 192.168.13.0/24 +#... +#lrp33 on ls3 for subnet 192.168.33.0/24 +# +# 27 VIFs, 9 per LS, 3 per subnet: lp[123][123][123], where the first two +# digits are the subnet and the last digit distinguishes the VIF. +for i in 1 2 3; do +ovn-nbctl lswitch-add ls$i +for j in 1 2 3; do +for k in 1 2 3; do +ovn-nbctl \ +-- lport-add ls$i lp$i$j$k \ +-- lport-set-addresses lp$i$j$k "f0:00:00:00:0$i:$j$k 192.168.$i$j.$k" +done +done +done + +# Physical network: +# +# Three hypervisors hv[123]. +# lp?1[123] spread across hv[123]: lp?11 on hv1, lp?12 on hv2, lp?13 on hv3. +# lp?2[123] spread across hv[23]: lp?21 and lp?22 on hv2, lp?23 on hv3. +# lp?3[123] all on hv3. + + +# Given the name of a logical port, prints the name of the hypervisor +# on which it is located. +vif_to_hv() { +case $1 in dnl ( +?11) echo 1 ;; dnl ( +?12 | ?21 | ?22) echo 2 ;; dnl ( +?13 | ?23 | ?3?) echo 3 ;; +esac +} + +# Given the name of a logical port, prints the name of its logical router +# port, e.g. "vif_to_lrp 123" yields 12. +vif_to_lrp() { +echo ${1%?} +} + +# Given the name of a logical port, prints the name of its logical +# switch, e.g. "vif_to_ls 123" yields 1. +vif_to_ls() { +echo ${1%??} +} + +net_add n1 +for i in 1 2 3; do +sim_add hv$i +as hv$i +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.$i +done +for i in 1 2 3; do +for j in 1 2 3; do +for k in 1 2 3; do +hv=`vif_to_hv $i$j$k` +as hv$hv ovs-vsctl \ +-- add-port br-int vif$i$j$k \ +-- set Interface vif$i$j$k \ + external-ids:iface-id=lp$i$j$k \ + options:tx_pcap=hv$hv/vif$i$j$k-tx.pcap \ + options:rxq_pcap=hv$hv/vif$i$j$k-rx.pcap \ + ofport-request=$i$j$k +done +done +done + +# Pre-populate the hypervisors' ARP tables so that we don't lose any +# packets for ARP resolution (native tunneling doesn't queue packets +# for ARP resolution). +ovn_populate_arp + +# Allow some time for ovn-northd and ovn-controller to catch up. +# XXX This should be more systematic. +sleep 1 + +send_dhcp_packet() { +local inport=$1 src_mac=$2 dhcp_type=$3 +local request=${src_mac}0800451001108011 +# udp header and dhcp header +request+=0044004300FC +request+=010106006359aa76${src_mac} +# client hardware padding +request+= +# server hostname +request+= +request+= +# boot file name +request+= +request+= +request+= +request+= +# dhcp magic cookie +request+=63825363 +# dhcp message type +request+=3501${dhcp_type}ff +shift; shift; shift; shift; shift +hv=`vif_to_hv $inport` +as hv$hv ovs-appctl netdev-dummy/receive vif$inport $request +} + +ip_to_hex() { +printf "%02x%02x%02x%02x" "$@" +} + +run_dhcp_test() { +local i=$1 j=$2 k=$3 set_option=$4 dhcp_type=$5 +netmask=255.255.255.0 +gw_ip=0.0.0.0 +if $set_option = 'true'; then +netmask=255.255.252.0 +gw_ip=192.168.$i$j.254 +ovn-nbctl \ +-- lport-set-options lp$i$j$k \ +"dhcp-opt-1=$netmask" "dhcp-opt-3=$gw_ip" +sleep 1 +fi + +echo $gw_ip +e