From d0cd93c1a04712544c83b45765b3c3f5bd2f9433 Mon Sep 17 00:00:00 2001 From: Dennis Date: Thu, 18 Jan 2018 10:33:22 -0800 Subject: [PATCH 01/45] Just some English correction Just some clarification in a sentence. --- doc/source/writing_ryu_app.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/writing_ryu_app.rst b/doc/source/writing_ryu_app.rst index 8f8556bb..ce68990b 100644 --- a/doc/source/writing_ryu_app.rst +++ b/doc/source/writing_ryu_app.rst @@ -41,7 +41,7 @@ application. In fact, you can run this Ryu application:: instantiating app /Users/fujita/l2.py -All you have to do is defining needs a new subclass of RyuApp to run +All you have to do is define a new subclass of RyuApp to run your Python script as a Ryu application. Next let's add the functionality of sending a received packet to all From d074e15a480ac6d29d61e511683cc9e03a81c037 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Wed, 3 Oct 2018 14:21:56 +0900 Subject: [PATCH 02/45] Ryu 4.29 Signed-off-by: FUJITA Tomonori --- ryu/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ryu/__init__.py b/ryu/__init__.py index a583da62..b4903c48 100644 --- a/ryu/__init__.py +++ b/ryu/__init__.py @@ -14,5 +14,5 @@ # limitations under the License. -version_info = (4, 28) +version_info = (4, 29) version = '.'.join(map(str, version_info)) From 1b38505909a47731e7f7293d08d9ad003ee3787d Mon Sep 17 00:00:00 2001 From: Bill Allen Date: Tue, 16 Oct 2018 21:14:00 +0100 Subject: [PATCH 03/45] Grammatical improvements to some of the documentation. Signed-off-by: Bill Allen Signed-off-by: FUJITA Tomonori --- README.rst | 10 +++---- doc/source/writing_ryu_app.rst | 48 +++++++++++++++++----------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/README.rst b/README.rst index 1a54ae7c..361ef599 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@ What's Ryu ========== Ryu is a component-based software defined networking framework. -Ryu provides software components with well defined API that make it +Ryu provides software components with well defined API's that make it easy for developers to create new network management and control applications. Ryu supports various protocols for managing network devices, such as OpenFlow, Netconf, OF-config, etc. About OpenFlow, @@ -33,14 +33,14 @@ After writing your application, just type:: Optional Requirements ===================== -Some functionalities of ryu requires extra packages: +Some functions of ryu require extra packages: - OF-Config requires lxml and ncclient - NETCONF requires paramiko - BGP speaker (SSH console) requires paramiko - Zebra protocol service (database) requires SQLAlchemy -If you want to use the functionalities, please install requirements:: +If you want to use these functions, please install the requirements:: % pip install -r tools/optional-requires @@ -49,8 +49,8 @@ Please refer to tools/optional-requires for details. Prerequisites ============= -If you got some error messages at installation step, please confirm -dependencies for building required Python packages. +If you got some error messages at the installation stage, please confirm +dependencies for building the required Python packages. On Ubuntu(16.04 LTS or later):: diff --git a/doc/source/writing_ryu_app.rst b/doc/source/writing_ryu_app.rst index 8f8556bb..7f15ed9a 100644 --- a/doc/source/writing_ryu_app.rst +++ b/doc/source/writing_ryu_app.rst @@ -5,21 +5,21 @@ The First Application Whetting Your Appetite ====================== -If you want to manage the network gears (switches, routers, etc) at -your way, you need to write your Ryu application. Your application -tells Ryu how you want to manage the gears. Then Ryu configures the -gears by using OpenFlow protocol, etc. +If you want to manage network gear (switches, routers, etc) your +own way, you just need to write your own Ryu application. Your application +tells Ryu how you want to manage the gear. Then Ryu configures the +gear by using OpenFlow protocol, etc. -Writing Ryu application is easy. It's just Python scripts. +Writing Ryu applications is easy. They're just Python scripts. Start Writing ============= -We show a Ryu application that make OpenFlow switches work as a dumb +Here we show a Ryu application that makes an OpenFlow switch work as a dumb layer 2 switch. -Open a text editor creating a new file with the following content: +Open a text editor and create a new file with the following content: .. code-block:: python @@ -29,9 +29,9 @@ Open a text editor creating a new file with the following content: def __init__(self, *args, **kwargs): super(L2Switch, self).__init__(*args, **kwargs) -Ryu application is just a Python script so you can save the file with -any name, extensions, and any place you want. Let's name the file -'l2.py' at your home directory. +Ryu applications are just Python scripts so you can save the file with +any name, any extension, and any place you want. Let's name the file +'l2.py' in your home directory. This application does nothing useful yet, however it's a complete Ryu application. In fact, you can run this Ryu application:: @@ -41,10 +41,10 @@ application. In fact, you can run this Ryu application:: instantiating app /Users/fujita/l2.py -All you have to do is defining needs a new subclass of RyuApp to run +All you have to do is define a new subclass of RyuApp to run your Python script as a Ryu application. -Next let's add the functionality of sending a received packet to all +Next let's add some functionality that sends a received packet to all the ports. .. code-block:: python @@ -75,18 +75,18 @@ the ports. dp.send_msg(out) -A new method 'packet_in_handler' is added to L2Switch class. This is -called when Ryu receives an OpenFlow packet_in message. The trick is +A new method 'packet_in_handler' is added to the L2Switch class. This is +called when Ryu receives an OpenFlow packet_in message. The trick is the 'set_ev_cls' decorator. This decorator tells Ryu when the decorated function should be called. -The first argument of the decorator indicates an event that makes -function called. As you expect easily, every time Ryu gets a +The first argument of the decorator indicates which type of event this +function should be called for. As you might expect, every time Ryu gets a packet_in message, this function is called. -The second argument indicates the state of the switch. Probably, you +The second argument indicates the state of the switch. You probably want to ignore packet_in messages before the negotiation between Ryu -and the switch finishes. Using 'MAIN_DISPATCHER' as the second +and the switch is finished. Using 'MAIN_DISPATCHER' as the second argument means this function is called only after the negotiation completes. @@ -103,20 +103,20 @@ Ready for the second half. * OFPActionOutput class is used with a packet_out message to specify a switch port that you want to send the packet out of. This - application need a switch to send out of all the ports so OFPP_FLOOD - constant is used. + application uses the OFPP_FLOOD flag to indicate that the packet should + be sent out on all ports. * OFPPacketOut class is used to build a packet_out message. * If you call Datapath class's send_msg method with a OpenFlow message - class object, Ryu builds and send the on-wire data format to the switch. + class object, Ryu builds and sends the on-wire data format to the switch. -Here, you finished implementing your first Ryu application. You are ready to -run this Ryu application that does something useful. +There, you finished implementing your first Ryu application. You are ready to +run a Ryu application that does something useful. -A dumb l2 switch is too dumb? You want to implement a learning l2 +Is a dumb L2 switch is too dumb? You want to implement a learning L2 switch? Move to `the next step `_. You can learn from the existing Ryu applications at `ryu/app From 56e8fb3f57894bca73f2445de9eb3ce282862f4e Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Sat, 3 Nov 2018 19:37:16 +0900 Subject: [PATCH 04/45] Ryu 4.30 Signed-off-by: FUJITA Tomonori --- ryu/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ryu/__init__.py b/ryu/__init__.py index b4903c48..caa84eec 100644 --- a/ryu/__init__.py +++ b/ryu/__init__.py @@ -14,5 +14,5 @@ # limitations under the License. -version_info = (4, 29) +version_info = (4, 30) version = '.'.join(map(str, version_info)) From 01a09a0e0208fe4519885ae2e9bcdbcdbe32aed7 Mon Sep 17 00:00:00 2001 From: IWAMOTO Toshihiro Date: Mon, 25 Mar 2019 14:43:23 +0900 Subject: [PATCH 05/45] Choose the highest TLS version Please note that this is a stop-gap measure. Also add a basic SSL server test. Co-authored-by: alex Signed-off-by: IWAMOTO Toshihiro Signed-off-by: FUJITA Tomonori --- ryu/controller/controller.py | 23 +++++++-- ryu/lib/hub.py | 13 ++++- ryu/tests/unit/controller/cert.crt | 21 ++++++++ ryu/tests/unit/controller/cert.key | 28 +++++++++++ ryu/tests/unit/controller/test_controller.py | 52 ++++++++++++++++++++ 5 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 ryu/tests/unit/controller/cert.crt create mode 100644 ryu/tests/unit/controller/cert.key diff --git a/ryu/controller/controller.py b/ryu/controller/controller.py index 62135339..b3d2d35b 100644 --- a/ryu/controller/controller.py +++ b/ryu/controller/controller.py @@ -165,6 +165,23 @@ class OpenFlowController(object): def server_loop(self, ofp_tcp_listen_port, ofp_ssl_listen_port): if CONF.ctl_privkey is not None and CONF.ctl_cert is not None: + if not hasattr(ssl, 'SSLContext'): + # anything less than python 2.7.9 supports only TLSv1 + # or less, thus we choose TLSv1 + ssl_args = {'ssl_version': ssl.PROTOCOL_TLSv1} + else: + # from 2.7.9 and versions 3.4+ ssl context creation is + # supported. Protocol_TLS from 2.7.13 and from 3.5.3 + # replaced SSLv23. Functionality is similar. + if hasattr(ssl, 'PROTOCOL_TLS'): + p = 'PROTOCOL_TLS' + else: + p = 'PROTOCOL_SSLv23' + + ssl_args = {'ssl_ctx': ssl.SSLContext(getattr(ssl, p))} + # Restrict non-safe versions + ssl_args['ssl_ctx'].options |= ssl.OP_NO_SSLv3 | ssl.OP_NO_SSLv2 + if CONF.ca_certs is not None: server = StreamServer((CONF.ofp_listen_host, ofp_ssl_listen_port), @@ -172,15 +189,13 @@ class OpenFlowController(object): keyfile=CONF.ctl_privkey, certfile=CONF.ctl_cert, cert_reqs=ssl.CERT_REQUIRED, - ca_certs=CONF.ca_certs, - ssl_version=ssl.PROTOCOL_TLSv1) + ca_certs=CONF.ca_certs, **ssl_args) else: server = StreamServer((CONF.ofp_listen_host, ofp_ssl_listen_port), datapath_connection_factory, keyfile=CONF.ctl_privkey, - certfile=CONF.ctl_cert, - ssl_version=ssl.PROTOCOL_TLSv1) + certfile=CONF.ctl_cert, **ssl_args) else: server = StreamServer((CONF.ofp_listen_host, ofp_tcp_listen_port), diff --git a/ryu/lib/hub.py b/ryu/lib/hub.py index bd15fc89..e847f656 100644 --- a/ryu/lib/hub.py +++ b/ryu/lib/hub.py @@ -42,6 +42,7 @@ if HUB_TYPE == 'eventlet': import ssl import socket import traceback + import sys getcurrent = eventlet.getcurrent patch = eventlet.monkey_patch @@ -128,7 +129,17 @@ if HUB_TYPE == 'eventlet': if ssl_args: def wrap_and_handle(sock, addr): ssl_args.setdefault('server_side', True) - handle(ssl.wrap_socket(sock, **ssl_args), addr) + if 'ssl_ctx' in ssl_args: + ctx = ssl_args.pop('ssl_ctx') + ctx.load_cert_chain(ssl_args.pop('certfile'), + ssl_args.pop('keyfile')) + if 'cert_reqs' in ssl_args: + ctx.verify_mode = ssl_args.pop('cert_reqs') + if 'ca_certs' in ssl_args: + ctx.load_verify_locations(ssl_args.pop('ca_certs')) + handle(ctx.wrap_socket(sock, **ssl_args), addr) + else: + handle(ssl.wrap_socket(sock, **ssl_args), addr) self.handle = wrap_and_handle else: diff --git a/ryu/tests/unit/controller/cert.crt b/ryu/tests/unit/controller/cert.crt new file mode 100644 index 00000000..e1b2afc4 --- /dev/null +++ b/ryu/tests/unit/controller/cert.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDaDCCAlCgAwIBAgIJAKL09YuU92JPMA0GCSqGSIb3DQEBCwUAMEgxCzAJBgNV +BAYTAkpQMRMwEQYDVQQIDApTb21lLVN0YXRlMSQwIgYDVQQKDBtSeXUgU0ROIEZy +YW1ld29yayBDb21tdW5pdHkwIBcNMTkwMzI1MDE1NzQzWhgPMjI5MzAxMDYwMTU3 +NDNaMEgxCzAJBgNVBAYTAkpQMRMwEQYDVQQIDApTb21lLVN0YXRlMSQwIgYDVQQK +DBtSeXUgU0ROIEZyYW1ld29yayBDb21tdW5pdHkwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDLT29+6JwD75wH7gPVxU52hrysBfxE6WjyT/nT+aSIQmZu +SU6/5hECOnV4YdyB7rxFu2WO2SD5PgeoHPBpTqtxrdTWoVOWVljnNcqEwSCS7bl9 +nbgX8uxCacg9qbFNJJRBAS0XQ2bSsD0GoOnhj3Olrz1u0wRIUqrR3A5giMbYwQPr +S4cmkxfgp2uV+WCHk40WxZnGgWzIRhO11GK9CAGncncPYhj+23w+GFaHIf00TdV2 +JEvwLFuLf1EaewZ7rz8zf1sLHAxqx20A6VdledEpNAzt1L8goPhk1mHvRgUC7E2v +FnSt1ePCJsVrvccudMdPBXSMfgJC2gmfdQefdSXRAgMBAAGjUzBRMB0GA1UdDgQW +BBRjlXSQ2rVjwOr1io6iJyidmjCNfzAfBgNVHSMEGDAWgBRjlXSQ2rVjwOr1io6i +JyidmjCNfzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCC1Uvo +4PdC5YQSXkAhrxgVhexp87VVkoWwpno75hvfoCjtSkb7+cskvQbPM14zbjIUrsli +qmTkjXyTUe8q5U06OitMAyM6qUvS0nFDi5aPQYV6N0XmJ+rV18prfQORyHvEmEyv +nqHVPoQkmGPpJ8aOVrTlECyxG7wLI2UxBEB3Atk51QHzbGGLKW7g5tHY6J5cMe/9 +ydeClJk2/AXkoqWkbtJrbw46alH97CajuLn/4D9B/Rm+M1Kg48gze5zJ7+WrB0Jl +pAhRqMM3upaOlXdeYDdNDgE0j/ulZGY2UssFIoHylcrb4QKQXjwqRXYhuuucJQJ3 +vsY4y1D/qps9llRL +-----END CERTIFICATE----- diff --git a/ryu/tests/unit/controller/cert.key b/ryu/tests/unit/controller/cert.key new file mode 100644 index 00000000..2b7f5f06 --- /dev/null +++ b/ryu/tests/unit/controller/cert.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQDLT29+6JwD75wH +7gPVxU52hrysBfxE6WjyT/nT+aSIQmZuSU6/5hECOnV4YdyB7rxFu2WO2SD5Pgeo +HPBpTqtxrdTWoVOWVljnNcqEwSCS7bl9nbgX8uxCacg9qbFNJJRBAS0XQ2bSsD0G +oOnhj3Olrz1u0wRIUqrR3A5giMbYwQPrS4cmkxfgp2uV+WCHk40WxZnGgWzIRhO1 +1GK9CAGncncPYhj+23w+GFaHIf00TdV2JEvwLFuLf1EaewZ7rz8zf1sLHAxqx20A +6VdledEpNAzt1L8goPhk1mHvRgUC7E2vFnSt1ePCJsVrvccudMdPBXSMfgJC2gmf +dQefdSXRAgMBAAECggEAcvPsB6Z/qB4Pa9Bg7LqNnaia/uy3cUND6lXb3MW3CK/6 +eHsMgqYTkd3502IJqpGQdCD70CPmZ+Zxr9UE/ZXUjAcMY3p952/U/o3EfwEvaMPu +8B6AG1Jn0Tk8VdkffY2kIYkHtLKQbanmJ1xOQRG6AsEti/7V2gqbuOKiYmSTgbPG +Upw9JNdtR6bZrGrrEXJbPCrSCej47MDyE+nt4zMIsqmY5IlbTMHcTKVDGeKbT9qT +7/Uyg+Tb62eber9iQhE0OteLt2GwrJR5yZ5QKNKM4SPqwYlOvQ9z289eZMVU3uwI +1NI1YRM5EMsdWrzFye7H/T/jsCaWrO0zmI/I4BMfEQKBgQDtUgPyY4PgVXVZ/hha +l5pi66GQ79+6LJP3SHb3I6p0iULq3oV+onG0Ezvx2vc21sbuLEazNlJoXzEzSIVM +/RjNJ9FsD/ENEuJedkspwtZZ4O4ZH6wKyHg/LCUly59ER37Ql/XwIX7adKCn7Z4d +9xN3aQmPtLna/aIZ8HyptRpT9QKBgQDbUB67YXiIFY+k5cwtK0m8T3rY4WNpEwzr +Y/1l+0EvXqCousU9MnLveyY8EcLDh5SnM0CvH4mFS8xL/r/kcUO9cHwuM+KZ77KN +Ukp9CRT9raxDZY/F0FVuET4LrJNnekCMsOnMxO51il/AHcul7886sEirkB1dsXND +nkh9h8g87QJ/cRikyN6j+kS/qCNvd7zH1lx0op2uAQs9eJsQFrbohKDlQwjIlZDU +nvyLlLbFGV1BcD+pcb5xh0vWJppo7EexihNvug/e0FwvhNTa/QvdGvgWf+KYGotu +wqxHB7wCKofn54CDs+xCh9kMtvqGX8FfhYiJBfMan0I//hydTEMCSQKBgEiv6E+g +gYtQ4hf8FczOsRSZnxSstv8HUlvd+wlG2hbyHPtvU5nx04gt38E+/bdCg3FbGlAw +eqrUMXTqjP0Q0SvDUVUa2zq76AjQwmFoli1x10tLKPieEQJ28oJ6Ayzjpus6Y3L7 +vjD02MFa3rkznxJLhPpfvGvmOVaq6km4rBQNAoGBALQGfaRiAtp6lSubi4Etdwtg +Tps2o1SBXfzENpq6s99k+UdCBLh90uzuA897GClsUYeuAYUyxQP3otIZUuSjq/Ht +JHYwT9QxOkSYrNCfQW/nF0CJjZ6TcvcFp8SdyUUbwCR2rkDK7LlMzxkfU3cCrwMP +q51oIVlKjIxg86JJXrRQ +-----END PRIVATE KEY----- diff --git a/ryu/tests/unit/controller/test_controller.py b/ryu/tests/unit/controller/test_controller.py index a94e7b43..45c659c9 100644 --- a/ryu/tests/unit/controller/test_controller.py +++ b/ryu/tests/unit/controller/test_controller.py @@ -22,6 +22,7 @@ except ImportError: import json import os +import ssl import sys import warnings import logging @@ -33,9 +34,11 @@ from nose.tools import eq_, raises from ryu.base import app_manager # To suppress cyclic import from ryu.controller import controller from ryu.controller import handler +from ryu.lib import hub from ryu.ofproto import ofproto_v1_3_parser from ryu.ofproto import ofproto_v1_2_parser from ryu.ofproto import ofproto_v1_0_parser +hub.patch() LOG = logging.getLogger('test_controller') @@ -177,3 +180,52 @@ class Test_Datapath(unittest.TestCase): self.assertEqual(state, handler.MAIN_DISPATCHER) self.assertEqual(kwargs, {}) self.assertEqual(expected_json, output_json) + + +class TestOpenFlowController(unittest.TestCase): + """ + Test cases for OpenFlowController + """ + @mock.patch("ryu.controller.controller.CONF") + def _test_ssl(self, this_dir, port, conf_mock): + conf_mock.ofp_ssl_listen_port = port + conf_mock.ofp_listen_host = "127.0.0.1" + conf_mock.ca_certs = None + conf_mock.ctl_cert = os.path.join(this_dir, 'cert.crt') + conf_mock.ctl_privkey = os.path.join(this_dir, 'cert.key') + c = controller.OpenFlowController() + c() + + def test_ssl(self): + """Tests SSL server functionality.""" + # TODO: TLS version enforcement is necessary to avoid + # vulnerable versions. Currently, this only tests TLS + # connectivity. + this_dir = os.path.dirname(sys.modules[__name__].__file__) + saved_exception = None + try: + ssl_version = ssl.PROTOCOL_TLS + except AttributeError: + # For compatibility with older pythons. + ssl_version = ssl.PROTOCOL_TLSv1 + for i in range(3): + try: + # Try a few times as this can fail with EADDRINUSE + port = random.randint(5000, 10000) + server = hub.spawn(self._test_ssl, this_dir, port) + hub.sleep(1) + client = hub.StreamClient(("127.0.0.1", port), + timeout=5, + ssl_version=ssl_version) + if client.connect() is not None: + break + except Exception as e: + saved_exception = e + continue + finally: + try: + hub.kill(server) + except Exception: + pass + else: + self.fail("Failed to connect: " + str(saved_exception)) From 050bfbc711ed9f3bcab458a904eab74aad90b076 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 1 Apr 2019 21:39:07 +0900 Subject: [PATCH 06/45] Ryu 4.31 Signed-off-by: FUJITA Tomonori --- ryu/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ryu/__init__.py b/ryu/__init__.py index caa84eec..e3227b31 100644 --- a/ryu/__init__.py +++ b/ryu/__init__.py @@ -14,5 +14,5 @@ # limitations under the License. -version_info = (4, 30) +version_info = (4, 31) version = '.'.join(map(str, version_info)) From 6f906e72c92e10bd0264c9b91a2f7bb85b97780c Mon Sep 17 00:00:00 2001 From: Atzm Watanabe Date: Fri, 29 Mar 2019 13:47:37 +0900 Subject: [PATCH 07/45] app/ofctl: fix possible deadlock When datapath reconnects/disconnects, waiting requests on old datapath should be canceled. Otherwise, threads that sent requests may fall into deadlock because replies possibly never come. Signed-off-by: Atzm Watanabe Signed-off-by: FUJITA Tomonori --- ryu/app/ofctl/service.py | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/ryu/app/ofctl/service.py b/ryu/app/ofctl/service.py index 08ee75bd..eed51774 100644 --- a/ryu/app/ofctl/service.py +++ b/ryu/app/ofctl/service.py @@ -64,6 +64,22 @@ class OfctlService(app_manager.RyuApp): self.unobserve_event(ev_cls) self.logger.debug('ofctl: stop observing %s', ev_cls) + def _cancel(self, info, barrier_xid, exception): + xid = info.barriers.pop(barrier_xid) + req = info.xids.pop(xid) + msg = req.msg + datapath = msg.datapath + parser = datapath.ofproto_parser + is_barrier = isinstance(msg, parser.OFPBarrierRequest) + + info.results.pop(xid) + + if not is_barrier and req.reply_cls is not None: + self._unobserve_msg(req.reply_cls) + + self.logger.error('failed to send message <%s>', req.msg) + self.reply_to_request(req, event.Reply(exception=exception)) + @staticmethod def _is_error(msg): return (ofp_event.ofp_msg_to_ev_cls(type(msg)) == @@ -81,6 +97,9 @@ class OfctlService(app_manager.RyuApp): self._switches[id] = new_info if old_info: old_info.datapath.close() + for xid in list(old_info.barriers): + self._cancel( + old_info, xid, exception.InvalidDatapath(result=id)) @set_ev_cls(ofp_event.EventOFPStateChange, DEAD_DISPATCHER) def _handle_dead(self, ev): @@ -96,6 +115,8 @@ class OfctlService(app_manager.RyuApp): if info.datapath is datapath: self.logger.debug('forget info %s', info) self._switches.pop(id) + for xid in list(info.barriers): + self._cancel(info, xid, exception.InvalidDatapath(result=id)) @set_ev_cls(event.GetDatapathRequest, MAIN_DISPATCHER) def _handle_get_datapath(self, req): @@ -131,15 +152,6 @@ class OfctlService(app_manager.RyuApp): si.xids[xid] = req si.barriers[barrier_xid] = xid - def _cancel(barrier_xid, exc): - xid = si.barriers.pop(barrier_xid) - si.results.pop(xid) - si.xids.pop(xid) - if not is_barrier and req.reply_cls is not None: - self._unobserve_msg(req.reply_cls) - self.logger.error('failed to send message <%s>', msg) - self.reply_to_request(req, event.Reply(exception=exc)) - if is_barrier: barrier = msg datapath.set_xid(barrier) @@ -152,12 +164,14 @@ class OfctlService(app_manager.RyuApp): datapath.set_xid(barrier) _store_xid(msg.xid, barrier.xid) if not datapath.send_msg(msg): - return _cancel(barrier.xid, - exception.InvalidDatapath(result=datapath.id)) + return self._cancel( + si, barrier.xid, + exception.InvalidDatapath(result=datapath.id)) if not datapath.send_msg(barrier): - return _cancel(barrier.xid, - exception.InvalidDatapath(result=datapath.id)) + return self._cancel( + si, barrier.xid, + exception.InvalidDatapath(result=datapath.id)) @set_ev_cls(ofp_event.EventOFPBarrierReply, MAIN_DISPATCHER) def _handle_barrier(self, ev): From faffcb80d429d6aee7d8ad31d428ab8c952767ec Mon Sep 17 00:00:00 2001 From: Diego Rossi Mafioletti Date: Thu, 11 Apr 2019 07:09:42 -0300 Subject: [PATCH 08/45] Update nx_actions.py, fixing a typo on example Change parser.NXActionResubmit to parser.NXActionResubmitTable, according to right OpenFlow action. --- ryu/ofproto/nx_actions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ryu/ofproto/nx_actions.py b/ryu/ofproto/nx_actions.py index 7f543471..ba48da1e 100644 --- a/ryu/ofproto/nx_actions.py +++ b/ryu/ofproto/nx_actions.py @@ -788,7 +788,7 @@ def generate(ofp_name, ofpp_name): Example:: - actions += [parser.NXActionResubmit(in_port=8080, + actions += [parser.NXActionResubmitTable(in_port=8080, table_id=10)] """ _subtype = nicira_ext.NXAST_RESUBMIT_TABLE From 6456711a343bd9999491bee2eb059c218170cc50 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 2 May 2019 18:55:39 +0900 Subject: [PATCH 09/45] Ryu 4.32 Signed-off-by: FUJITA Tomonori --- ryu/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ryu/__init__.py b/ryu/__init__.py index e3227b31..bd6471bf 100644 --- a/ryu/__init__.py +++ b/ryu/__init__.py @@ -14,5 +14,5 @@ # limitations under the License. -version_info = (4, 31) +version_info = (4, 32) version = '.'.join(map(str, version_info)) From 550e89067127538ed41ae38128c479af21f75051 Mon Sep 17 00:00:00 2001 From: Ozgur Yurekten Date: Mon, 15 Jul 2019 14:08:25 +0300 Subject: [PATCH 10/45] nx_action_encap and nx_action_decap classes are defined Signed-off-by: Ozgur Yurekten Signed-off-by: FUJITA Tomonori --- ryu/ofproto/nicira_ext.py | 2 ++ ryu/ofproto/nx_actions.py | 74 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/ryu/ofproto/nicira_ext.py b/ryu/ofproto/nicira_ext.py index 9ac673a3..19c8394c 100644 --- a/ryu/ofproto/nicira_ext.py +++ b/ryu/ofproto/nicira_ext.py @@ -63,6 +63,8 @@ NXAST_CONTROLLER2 = 37 NXAST_SAMPLE2 = 38 NXAST_OUTPUT_TRUNC = 39 NXAST_CT_CLEAR = 43 +NXAST_RAW_ENCAP = 46 +NXAST_RAW_DECAP = 47 NXAST_DEC_NSH_TTL = 48 NX_ACTION_RESUBMIT_PACK_STR = '!HHIHHB3x' diff --git a/ryu/ofproto/nx_actions.py b/ryu/ofproto/nx_actions.py index 7f543471..5707ca17 100644 --- a/ryu/ofproto/nx_actions.py +++ b/ryu/ofproto/nx_actions.py @@ -2999,6 +2999,78 @@ def generate(ofp_name, ofpp_name): self.max_len) return data + class NXActionEncapEther(NXAction): + """ + Encap Ether + + This action encaps package with ethernet + + And equivalent to the followings action of ovs-ofctl command. + + :: + + encap(ethernet) + + Example:: + + actions += [parser.NXActionEncapEther()] + """ + _subtype = nicira_ext.NXAST_RAW_ENCAP + + _fmt_str = '!HI' + + def __init__(self, + type_=None, len_=None, vendor=None, subtype=None): + super(NXActionEncapEther, self).__init__() + self.hdr_size = 0 + self.new_pkt_type = 0x00000000 + + @classmethod + def parser(cls, buf): + return cls() + + def serialize_body(self): + data = bytearray() + msg_pack_into(self._fmt_str, data, 0, self.hdr_size, self.new_pkt_type) + return data + + + + class NXActionEncapNsh(NXAction): + """ + Encap nsh + + This action encaps package with nsh + + And equivalent to the followings action of ovs-ofctl command. + + :: + + encap(nsh(md_type=1)) + + Example:: + + actions += [parser.NXActionEncapNsh()] + """ + _subtype = nicira_ext.NXAST_RAW_ENCAP + + _fmt_str = '!HI' + + def __init__(self, + type_=None, len_=None, vendor=None, subtype=None): + super(NXActionEncapNsh, self).__init__() + self.hdr_size = hdr_size + self.new_pkt_type = 0x0001894F + + @classmethod + def parser(cls, buf): + return cls() + + def serialize_body(self): + data = bytearray() + msg_pack_into(self._fmt_str, data, 0, self.hdr_size, self.new_pkt_type) + return data + class NXActionDecNshTtl(NXAction): """ Decrement NSH TTL action @@ -3083,6 +3155,8 @@ def generate(ofp_name, ofpp_name): 'NXFlowSpecMatch', 'NXFlowSpecLoad', 'NXFlowSpecOutput', + 'NXActionEncapNsh', + 'NXActionEncapEther', 'NXActionDecNshTtl', ] vars = locals() From a295810f77238c5c55fc852d4807f0e46a298245 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 18 Jul 2019 20:46:08 +0900 Subject: [PATCH 11/45] fix style errors Signed-off-by: FUJITA Tomonori --- ryu/ofproto/nx_actions.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/ryu/ofproto/nx_actions.py b/ryu/ofproto/nx_actions.py index 5707ca17..bdb36406 100644 --- a/ryu/ofproto/nx_actions.py +++ b/ryu/ofproto/nx_actions.py @@ -3034,8 +3034,6 @@ def generate(ofp_name, ofpp_name): msg_pack_into(self._fmt_str, data, 0, self.hdr_size, self.new_pkt_type) return data - - class NXActionEncapNsh(NXAction): """ Encap nsh From bc111ac10dba7aeaf9787b769f94f06502eeaf61 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 1 Aug 2019 16:09:20 +0900 Subject: [PATCH 12/45] Ryu 4.33 Signed-off-by: FUJITA Tomonori --- ryu/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ryu/__init__.py b/ryu/__init__.py index bd6471bf..434aadb4 100644 --- a/ryu/__init__.py +++ b/ryu/__init__.py @@ -14,5 +14,5 @@ # limitations under the License. -version_info = (4, 32) +version_info = (4, 33) version = '.'.join(map(str, version_info)) From 29b8d7d28b447a614fdf5e4c3ec20c4c53ac710b Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 1 Aug 2019 16:27:36 +0900 Subject: [PATCH 13/45] drop Python 3.4 CI test Python 3.4 is officially dead. Signed-off-by: FUJITA Tomonori --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4f67934d..712ffd12 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,9 +14,6 @@ matrix: - python: 2.7 env: TOX_ENV=py27 - - python: 3.4 - env: TOX_ENV=py34 - - python: 3.5 env: TOX_ENV=py35 From d1b1b471e7e202e9955d230de01aae0702fcdb7c Mon Sep 17 00:00:00 2001 From: Benjamin Villain Date: Thu, 19 Sep 2019 17:14:37 +1000 Subject: [PATCH 14/45] Add support for Adj-RIB-Out (draft-ietf-grow-bmp-adj-rib-out-03) --- ryu/lib/packet/bmp.py | 49 +++++++++++++++++++++++-------- ryu/tests/unit/packet/test_bmp.py | 21 ++++++++++++- 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/ryu/lib/packet/bmp.py b/ryu/lib/packet/bmp.py index 0b4c3b84..1320dd2e 100644 --- a/ryu/lib/packet/bmp.py +++ b/ryu/lib/packet/bmp.py @@ -60,6 +60,8 @@ BMP_STAT_TYPE_INV_UPDATE_DUE_TO_ORIGINATOR_ID = 5 BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_CONFED_LOOP = 6 BMP_STAT_TYPE_ADJ_RIB_IN = 7 BMP_STAT_TYPE_LOC_RIB = 8 +BMP_STAT_TYPE_ADJ_RIB_OUT = 14 +BMP_STAT_TYPE_EXPORT_RIB = 15 BMP_PEER_DOWN_REASON_UNKNOWN = 0 BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION = 1 @@ -157,7 +159,8 @@ class BMPPeerMessage(BMPMessage): type Type field. one of BMP\_MSG\_ constants. peer_type The type of the peer. is_post_policy Indicate the message reflects the post-policy - Adj-RIB-In + is_adj_rib_out Indicate the message reflects Adj-RIB-Out (defaults + to Adj-RIB-In) peer_distinguisher Use for L3VPN router which can have multiple instance. peer_address The remote IP address associated with the TCP @@ -179,12 +182,13 @@ class BMPPeerMessage(BMPMessage): def __init__(self, peer_type, is_post_policy, peer_distinguisher, peer_address, peer_as, peer_bgp_id, timestamp, - version=VERSION, type_=None, len_=None): + version=VERSION, type_=None, len_=None, is_adj_rib_out=False): super(BMPPeerMessage, self).__init__(version=version, len_=len_, type_=type_) self.peer_type = peer_type self.is_post_policy = is_post_policy + self.is_adj_rib_out = is_adj_rib_out self.peer_distinguisher = peer_distinguisher self.peer_address = peer_address self.peer_as = peer_as @@ -200,6 +204,11 @@ class BMPPeerMessage(BMPMessage): rest = buf[struct.calcsize(cls._PEER_HDR_PACK_STR):] + if peer_flags & (1 << 4): + is_adj_rib_out = True + else: + is_adj_rib_out = False + if peer_flags & (1 << 6): is_post_policy = True else: @@ -221,12 +230,16 @@ class BMPPeerMessage(BMPMessage): "peer_address": peer_address, "peer_as": peer_as, "peer_bgp_id": peer_bgp_id, - "timestamp": timestamp + "timestamp": timestamp, + "is_adj_rib_out": is_adj_rib_out, }, rest def serialize_tail(self): flags = 0 + if self.is_adj_rib_out: + flags |= (1 << 4) + if self.is_post_policy: flags |= (1 << 6) @@ -275,7 +288,7 @@ class BMPRouteMonitoring(BMPPeerMessage): def __init__(self, bgp_update, peer_type, is_post_policy, peer_distinguisher, peer_address, peer_as, peer_bgp_id, timestamp, version=VERSION, type_=BMP_MSG_ROUTE_MONITORING, - len_=None): + len_=None, is_adj_rib_out=False): super(BMPRouteMonitoring, self).__init__(peer_type=peer_type, is_post_policy=is_post_policy, @@ -286,7 +299,8 @@ class BMPRouteMonitoring(BMPPeerMessage): timestamp=timestamp, len_=len_, type_=type_, - version=version) + version=version, + is_adj_rib_out=is_adj_rib_out) self.bgp_update = bgp_update @classmethod @@ -335,7 +349,8 @@ class BMPStatisticsReport(BMPPeerMessage): def __init__(self, stats, peer_type, is_post_policy, peer_distinguisher, peer_address, peer_as, peer_bgp_id, timestamp, - version=VERSION, type_=BMP_MSG_STATISTICS_REPORT, len_=None): + version=VERSION, type_=BMP_MSG_STATISTICS_REPORT, len_=None, + is_adj_rib_out=False): super(BMPStatisticsReport, self).__init__(peer_type=peer_type, is_post_policy=is_post_policy, @@ -346,7 +361,8 @@ class BMPStatisticsReport(BMPPeerMessage): timestamp=timestamp, len_=len_, type_=type_, - version=version) + version=version, + is_adj_rib_out=is_adj_rib_out) self.stats = stats @classmethod @@ -381,7 +397,9 @@ class BMPStatisticsReport(BMPPeerMessage): type_ == BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_CONFED_LOOP: value, = struct.unpack_from('!I', six.binary_type(value)) elif type_ == BMP_STAT_TYPE_ADJ_RIB_IN or \ - type_ == BMP_STAT_TYPE_LOC_RIB: + type_ == BMP_STAT_TYPE_LOC_RIB or \ + type_ == BMP_STAT_TYPE_ADJ_RIB_OUT or \ + type_ == BMP_STAT_TYPE_EXPORT_RIB: value, = struct.unpack_from('!Q', six.binary_type(value)) buf = buf[cls._MIN_LEN + len_:] @@ -410,7 +428,9 @@ class BMPStatisticsReport(BMPPeerMessage): t == BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_CONFED_LOOP: valuepackstr = 'I' elif t == BMP_STAT_TYPE_ADJ_RIB_IN or \ - t == BMP_STAT_TYPE_LOC_RIB: + t == BMP_STAT_TYPE_LOC_RIB or \ + t == BMP_STAT_TYPE_ADJ_RIB_OUT or \ + t == BMP_STAT_TYPE_EXPORT_RIB: valuepackstr = 'Q' else: continue @@ -440,7 +460,8 @@ class BMPPeerDownNotification(BMPPeerMessage): def __init__(self, reason, data, peer_type, is_post_policy, peer_distinguisher, peer_address, peer_as, peer_bgp_id, timestamp, version=VERSION, - type_=BMP_MSG_PEER_DOWN_NOTIFICATION, len_=None): + type_=BMP_MSG_PEER_DOWN_NOTIFICATION, len_=None, + is_adj_rib_out=False): super(BMPPeerDownNotification, self).__init__(peer_type=peer_type, @@ -452,7 +473,8 @@ class BMPPeerDownNotification(BMPPeerMessage): timestamp=timestamp, len_=len_, type_=type_, - version=version) + version=version, + is_adj_rib_out=is_adj_rib_out) self.reason = reason self.data = data @@ -537,7 +559,7 @@ class BMPPeerUpNotification(BMPPeerMessage): peer_type, is_post_policy, peer_distinguisher, peer_address, peer_as, peer_bgp_id, timestamp, version=VERSION, type_=BMP_MSG_PEER_UP_NOTIFICATION, - len_=None): + len_=None, is_adj_rib_out=False): super(BMPPeerUpNotification, self).__init__(peer_type=peer_type, is_post_policy=is_post_policy, @@ -548,7 +570,8 @@ class BMPPeerUpNotification(BMPPeerMessage): timestamp=timestamp, len_=len_, type_=type_, - version=version) + version=version, + is_adj_rib_out=is_adj_rib_out) self.local_address = local_address self.local_port = local_port self.remote_port = remote_port diff --git a/ryu/tests/unit/packet/test_bmp.py b/ryu/tests/unit/packet/test_bmp.py index f93b8014..d0bffecf 100644 --- a/ryu/tests/unit/packet/test_bmp.py +++ b/ryu/tests/unit/packet/test_bmp.py @@ -54,12 +54,31 @@ class Test_bmp(unittest.TestCase): eq_(msg.to_jsondict(), msg2.to_jsondict()) eq_(rest, b'') + def test_route_monitoring_adj_rib_out(self): + update = bgp.BGPUpdate() + msg = bmp.BMPRouteMonitoring(bgp_update=update, + peer_type=bmp.BMP_PEER_TYPE_GLOBAL, + is_post_policy=True, + is_adj_rib_out=True, + peer_distinguisher=0, + peer_address='192.0.2.1', + peer_as=30000, + peer_bgp_id='192.0.2.1', + timestamp=self._time()) + binmsg = msg.serialize() + msg2, rest = bmp.BMPMessage.parser(binmsg) + eq_(msg.to_jsondict(), msg2.to_jsondict()) + eq_(rest, b'') + def test_statistics_report(self): stats = [{'type': bmp.BMP_STAT_TYPE_REJECTED, 'value': 100}, {'type': bmp.BMP_STAT_TYPE_DUPLICATE_PREFIX, 'value': 200}, {'type': bmp.BMP_STAT_TYPE_DUPLICATE_WITHDRAW, 'value': 300}, {'type': bmp.BMP_STAT_TYPE_ADJ_RIB_IN, 'value': 100000}, - {'type': bmp.BMP_STAT_TYPE_LOC_RIB, 'value': 500000}] + {'type': bmp.BMP_STAT_TYPE_LOC_RIB, 'value': 500000}, + {'type': bmp.BMP_STAT_TYPE_ADJ_RIB_OUT, 'value': 95000}, + {'type': bmp.BMP_STAT_TYPE_EXPORT_RIB, 'value': 50000}, + {'type': bmp.BMP_STAT_TYPE_EXPORT_RIB, 'value': 50000}] msg = bmp.BMPStatisticsReport(stats=stats, peer_type=bmp.BMP_PEER_TYPE_GLOBAL, is_post_policy=True, From 4e0fc9e72d2048d272787956f648f19fb9e7158c Mon Sep 17 00:00:00 2001 From: Benjamin Villain via Ryu-devel Date: Tue, 24 Sep 2019 08:48:28 +1000 Subject: [PATCH 15/45] Add support for Adj-RIB-Out (draft-ietf-grow-bmp-adj-rib-out-03) Signed-off-by: Benjamin Villain Signed-off-by: FUJITA Tomonori --- ryu/lib/packet/bmp.py | 49 +++++++++++++++++++++++-------- ryu/tests/unit/packet/test_bmp.py | 21 ++++++++++++- 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/ryu/lib/packet/bmp.py b/ryu/lib/packet/bmp.py index 0b4c3b84..1320dd2e 100644 --- a/ryu/lib/packet/bmp.py +++ b/ryu/lib/packet/bmp.py @@ -60,6 +60,8 @@ BMP_STAT_TYPE_INV_UPDATE_DUE_TO_ORIGINATOR_ID = 5 BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_CONFED_LOOP = 6 BMP_STAT_TYPE_ADJ_RIB_IN = 7 BMP_STAT_TYPE_LOC_RIB = 8 +BMP_STAT_TYPE_ADJ_RIB_OUT = 14 +BMP_STAT_TYPE_EXPORT_RIB = 15 BMP_PEER_DOWN_REASON_UNKNOWN = 0 BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION = 1 @@ -157,7 +159,8 @@ class BMPPeerMessage(BMPMessage): type Type field. one of BMP\_MSG\_ constants. peer_type The type of the peer. is_post_policy Indicate the message reflects the post-policy - Adj-RIB-In + is_adj_rib_out Indicate the message reflects Adj-RIB-Out (defaults + to Adj-RIB-In) peer_distinguisher Use for L3VPN router which can have multiple instance. peer_address The remote IP address associated with the TCP @@ -179,12 +182,13 @@ class BMPPeerMessage(BMPMessage): def __init__(self, peer_type, is_post_policy, peer_distinguisher, peer_address, peer_as, peer_bgp_id, timestamp, - version=VERSION, type_=None, len_=None): + version=VERSION, type_=None, len_=None, is_adj_rib_out=False): super(BMPPeerMessage, self).__init__(version=version, len_=len_, type_=type_) self.peer_type = peer_type self.is_post_policy = is_post_policy + self.is_adj_rib_out = is_adj_rib_out self.peer_distinguisher = peer_distinguisher self.peer_address = peer_address self.peer_as = peer_as @@ -200,6 +204,11 @@ class BMPPeerMessage(BMPMessage): rest = buf[struct.calcsize(cls._PEER_HDR_PACK_STR):] + if peer_flags & (1 << 4): + is_adj_rib_out = True + else: + is_adj_rib_out = False + if peer_flags & (1 << 6): is_post_policy = True else: @@ -221,12 +230,16 @@ class BMPPeerMessage(BMPMessage): "peer_address": peer_address, "peer_as": peer_as, "peer_bgp_id": peer_bgp_id, - "timestamp": timestamp + "timestamp": timestamp, + "is_adj_rib_out": is_adj_rib_out, }, rest def serialize_tail(self): flags = 0 + if self.is_adj_rib_out: + flags |= (1 << 4) + if self.is_post_policy: flags |= (1 << 6) @@ -275,7 +288,7 @@ class BMPRouteMonitoring(BMPPeerMessage): def __init__(self, bgp_update, peer_type, is_post_policy, peer_distinguisher, peer_address, peer_as, peer_bgp_id, timestamp, version=VERSION, type_=BMP_MSG_ROUTE_MONITORING, - len_=None): + len_=None, is_adj_rib_out=False): super(BMPRouteMonitoring, self).__init__(peer_type=peer_type, is_post_policy=is_post_policy, @@ -286,7 +299,8 @@ class BMPRouteMonitoring(BMPPeerMessage): timestamp=timestamp, len_=len_, type_=type_, - version=version) + version=version, + is_adj_rib_out=is_adj_rib_out) self.bgp_update = bgp_update @classmethod @@ -335,7 +349,8 @@ class BMPStatisticsReport(BMPPeerMessage): def __init__(self, stats, peer_type, is_post_policy, peer_distinguisher, peer_address, peer_as, peer_bgp_id, timestamp, - version=VERSION, type_=BMP_MSG_STATISTICS_REPORT, len_=None): + version=VERSION, type_=BMP_MSG_STATISTICS_REPORT, len_=None, + is_adj_rib_out=False): super(BMPStatisticsReport, self).__init__(peer_type=peer_type, is_post_policy=is_post_policy, @@ -346,7 +361,8 @@ class BMPStatisticsReport(BMPPeerMessage): timestamp=timestamp, len_=len_, type_=type_, - version=version) + version=version, + is_adj_rib_out=is_adj_rib_out) self.stats = stats @classmethod @@ -381,7 +397,9 @@ class BMPStatisticsReport(BMPPeerMessage): type_ == BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_CONFED_LOOP: value, = struct.unpack_from('!I', six.binary_type(value)) elif type_ == BMP_STAT_TYPE_ADJ_RIB_IN or \ - type_ == BMP_STAT_TYPE_LOC_RIB: + type_ == BMP_STAT_TYPE_LOC_RIB or \ + type_ == BMP_STAT_TYPE_ADJ_RIB_OUT or \ + type_ == BMP_STAT_TYPE_EXPORT_RIB: value, = struct.unpack_from('!Q', six.binary_type(value)) buf = buf[cls._MIN_LEN + len_:] @@ -410,7 +428,9 @@ class BMPStatisticsReport(BMPPeerMessage): t == BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_CONFED_LOOP: valuepackstr = 'I' elif t == BMP_STAT_TYPE_ADJ_RIB_IN or \ - t == BMP_STAT_TYPE_LOC_RIB: + t == BMP_STAT_TYPE_LOC_RIB or \ + t == BMP_STAT_TYPE_ADJ_RIB_OUT or \ + t == BMP_STAT_TYPE_EXPORT_RIB: valuepackstr = 'Q' else: continue @@ -440,7 +460,8 @@ class BMPPeerDownNotification(BMPPeerMessage): def __init__(self, reason, data, peer_type, is_post_policy, peer_distinguisher, peer_address, peer_as, peer_bgp_id, timestamp, version=VERSION, - type_=BMP_MSG_PEER_DOWN_NOTIFICATION, len_=None): + type_=BMP_MSG_PEER_DOWN_NOTIFICATION, len_=None, + is_adj_rib_out=False): super(BMPPeerDownNotification, self).__init__(peer_type=peer_type, @@ -452,7 +473,8 @@ class BMPPeerDownNotification(BMPPeerMessage): timestamp=timestamp, len_=len_, type_=type_, - version=version) + version=version, + is_adj_rib_out=is_adj_rib_out) self.reason = reason self.data = data @@ -537,7 +559,7 @@ class BMPPeerUpNotification(BMPPeerMessage): peer_type, is_post_policy, peer_distinguisher, peer_address, peer_as, peer_bgp_id, timestamp, version=VERSION, type_=BMP_MSG_PEER_UP_NOTIFICATION, - len_=None): + len_=None, is_adj_rib_out=False): super(BMPPeerUpNotification, self).__init__(peer_type=peer_type, is_post_policy=is_post_policy, @@ -548,7 +570,8 @@ class BMPPeerUpNotification(BMPPeerMessage): timestamp=timestamp, len_=len_, type_=type_, - version=version) + version=version, + is_adj_rib_out=is_adj_rib_out) self.local_address = local_address self.local_port = local_port self.remote_port = remote_port diff --git a/ryu/tests/unit/packet/test_bmp.py b/ryu/tests/unit/packet/test_bmp.py index f93b8014..d0bffecf 100644 --- a/ryu/tests/unit/packet/test_bmp.py +++ b/ryu/tests/unit/packet/test_bmp.py @@ -54,12 +54,31 @@ class Test_bmp(unittest.TestCase): eq_(msg.to_jsondict(), msg2.to_jsondict()) eq_(rest, b'') + def test_route_monitoring_adj_rib_out(self): + update = bgp.BGPUpdate() + msg = bmp.BMPRouteMonitoring(bgp_update=update, + peer_type=bmp.BMP_PEER_TYPE_GLOBAL, + is_post_policy=True, + is_adj_rib_out=True, + peer_distinguisher=0, + peer_address='192.0.2.1', + peer_as=30000, + peer_bgp_id='192.0.2.1', + timestamp=self._time()) + binmsg = msg.serialize() + msg2, rest = bmp.BMPMessage.parser(binmsg) + eq_(msg.to_jsondict(), msg2.to_jsondict()) + eq_(rest, b'') + def test_statistics_report(self): stats = [{'type': bmp.BMP_STAT_TYPE_REJECTED, 'value': 100}, {'type': bmp.BMP_STAT_TYPE_DUPLICATE_PREFIX, 'value': 200}, {'type': bmp.BMP_STAT_TYPE_DUPLICATE_WITHDRAW, 'value': 300}, {'type': bmp.BMP_STAT_TYPE_ADJ_RIB_IN, 'value': 100000}, - {'type': bmp.BMP_STAT_TYPE_LOC_RIB, 'value': 500000}] + {'type': bmp.BMP_STAT_TYPE_LOC_RIB, 'value': 500000}, + {'type': bmp.BMP_STAT_TYPE_ADJ_RIB_OUT, 'value': 95000}, + {'type': bmp.BMP_STAT_TYPE_EXPORT_RIB, 'value': 50000}, + {'type': bmp.BMP_STAT_TYPE_EXPORT_RIB, 'value': 50000}] msg = bmp.BMPStatisticsReport(stats=stats, peer_type=bmp.BMP_PEER_TYPE_GLOBAL, is_post_policy=True, From 0866cb7d48c9ca7e6eaf9c89909fadd6c76f67d3 Mon Sep 17 00:00:00 2001 From: Benjamin Villain via Ryu-devel Date: Tue, 24 Sep 2019 08:52:48 +1000 Subject: [PATCH 16/45] Add support for revised RFC8227 withdraw labels This commit fixes a parsing error when a BGP update contains a "withdraw label" equal to 0x000000 instead of 0x8000000 as stated in RFC 3107. This commits treats both labels as "withdraw label" Signed-off-by: Benjamin Villain Signed-off-by: FUJITA Tomonori --- ryu/lib/packet/bgp.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/ryu/lib/packet/bgp.py b/ryu/lib/packet/bgp.py index 9e501515..89ed191e 100644 --- a/ryu/lib/packet/bgp.py +++ b/ryu/lib/packet/bgp.py @@ -782,7 +782,16 @@ class _LabelledAddrPrefix(_AddrPrefix): # Routes field should be set to 0x800000. (Of course, terminating the # BGP session also withdraws all the previously advertised routes.) # - _WITHDRAW_LABEL = 0x800000 + # RFC8227 + # 2.4 How to Explicitly Withdraw the Binding of a Label to a Prefix + # [RFC3107] also made it possible to withdraw a binding without specifying + # the label explicitly, by setting the Compatibility field to 0x800000. + # However, some implementations set it to 0x000000. In order to ensure + # backwards compatibility, it is RECOMMENDED by this document that the + # Compatibility field be set to 0x800000, but it is REQUIRED that it be + # ignored upon reception. + # + _WITHDRAW_LABELS = [0x800000, 0x000000] def __init__(self, length, addr, labels=None, **kwargs): labels = labels if labels else [] @@ -823,7 +832,7 @@ class _LabelledAddrPrefix(_AddrPrefix): labels = addr[0] rest = addr[1:] labels = [x << 4 for x in labels] - if labels and labels[-1] != cls._WITHDRAW_LABEL: + if labels and labels[-1] not in cls._WITHDRAW_LABELS: labels[-1] |= 1 # bottom of stack bin_labels = list(cls._label_to_bin(l) for l in labels) return bytes(reduce(lambda x, y: x + y, bin_labels, @@ -837,7 +846,7 @@ class _LabelledAddrPrefix(_AddrPrefix): while True: (label, bin_) = cls._label_from_bin(bin_) labels.append(label) - if label & 1 or label == cls._WITHDRAW_LABEL: + if label & 1 or label in cls._WITHDRAW_LABELS: break assert length > struct.calcsize(cls._LABEL_PACK_STR) * len(labels) except struct.error: @@ -857,7 +866,7 @@ class _LabelledAddrPrefix(_AddrPrefix): while True: (label, rest) = cls._label_from_bin(rest) labels.append(label >> 4) - if label & 1 or label == cls._WITHDRAW_LABEL: + if label & 1 or label in cls._WITHDRAW_LABELS: break return (labels,) + cls._prefix_from_bin(rest) From c776e4cb68600b2ee0a4f38364f4a355502777f1 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 1 Oct 2019 19:42:10 +0900 Subject: [PATCH 17/45] Ryu 4.34 Signed-off-by: FUJITA Tomonori --- ryu/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ryu/__init__.py b/ryu/__init__.py index 434aadb4..dae366a0 100644 --- a/ryu/__init__.py +++ b/ryu/__init__.py @@ -14,5 +14,5 @@ # limitations under the License. -version_info = (4, 33) +version_info = (4, 34) version = '.'.join(map(str, version_info)) From e3ebed794332ca23a0f67580fd3230612d9d7b07 Mon Sep 17 00:00:00 2001 From: Adrian Freund Date: Wed, 27 Nov 2019 13:18:39 +0100 Subject: [PATCH 18/45] Restrict tinyrpc to version 0.9.4 as newer versions break python2 support --- tools/pip-requires | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pip-requires b/tools/pip-requires index 47c6d02a..56020060 100644 --- a/tools/pip-requires +++ b/tools/pip-requires @@ -8,5 +8,5 @@ oslo.config>=2.5.0 ovs>=2.6.0 # OVSDB routes # wsgi six>=1.4.0 -tinyrpc # RPC library, BGP speaker(net_cntl) +tinyrpc==0.9.4 # RPC library, BGP speaker(net_cntl) webob>=1.2 # wsgi From be289978c7883a8343faee723f6324f52943d23f Mon Sep 17 00:00:00 2001 From: Grant Curell Date: Wed, 1 Apr 2020 10:12:31 -0500 Subject: [PATCH 19/45] Fix two bugs in simple switch 13 examples - dpid with leading 0s would be truncated to less than 16 characters - Response object incorrectly used body type when it should use text --- ryu/app/simple_switch_13.py | 2 +- ryu/app/simple_switch_rest_13.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ryu/app/simple_switch_13.py b/ryu/app/simple_switch_13.py index 06a5d0ed..907425c9 100644 --- a/ryu/app/simple_switch_13.py +++ b/ryu/app/simple_switch_13.py @@ -85,7 +85,7 @@ class SimpleSwitch13(app_manager.RyuApp): dst = eth.dst src = eth.src - dpid = datapath.id + dpid = format(datapath.id, "d").zfill(16) self.mac_to_port.setdefault(dpid, {}) self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port) diff --git a/ryu/app/simple_switch_rest_13.py b/ryu/app/simple_switch_rest_13.py index aaf5d509..31f834f0 100644 --- a/ryu/app/simple_switch_rest_13.py +++ b/ryu/app/simple_switch_rest_13.py @@ -85,21 +85,21 @@ class SimpleSwitchController(ControllerBase): def list_mac_table(self, req, **kwargs): simple_switch = self.simple_switch_app - dpid = dpid_lib.str_to_dpid(kwargs['dpid']) + dpid = kwargs['dpid'] if dpid not in simple_switch.mac_to_port: return Response(status=404) mac_table = simple_switch.mac_to_port.get(dpid, {}) body = json.dumps(mac_table) - return Response(content_type='application/json', body=body) + return Response(content_type='application/json', text=body) @route('simpleswitch', url, methods=['PUT'], requirements={'dpid': dpid_lib.DPID_PATTERN}) def put_mac_table(self, req, **kwargs): simple_switch = self.simple_switch_app - dpid = dpid_lib.str_to_dpid(kwargs['dpid']) + dpid = kwargs['dpid'] try: new_entry = req.json if req.body else {} except ValueError: @@ -111,6 +111,6 @@ class SimpleSwitchController(ControllerBase): try: mac_table = simple_switch.set_mac_to_port(dpid, new_entry) body = json.dumps(mac_table) - return Response(content_type='application/json', body=body) + return Response(content_type='application/json', text=body) except Exception as e: return Response(status=500) From c34337684964029ffd4fc5653633892863942fd6 Mon Sep 17 00:00:00 2001 From: Scott Date: Wed, 22 Apr 2020 17:09:47 +1200 Subject: [PATCH 20/45] updated jsonrpc.Session call to have correct arguments for latest version of ovs Signed-off-by: Scott --- ryu/services/protocols/ovsdb/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ryu/services/protocols/ovsdb/client.py b/ryu/services/protocols/ovsdb/client.py index 6ea36842..3f8b4304 100644 --- a/ryu/services/protocols/ovsdb/client.py +++ b/ryu/services/protocols/ovsdb/client.py @@ -319,7 +319,7 @@ class RemoteOvsdb(app_manager.RyuApp): fsm.connected(now()) - session = jsonrpc.Session(fsm, connection) + session = jsonrpc.Session(fsm, connection, fsm.get_name()) idl = Idl(session, schemas[0]) system_id = discover_system_id(idl) From 5fd42fff66352137d085de83173b945c674a9033 Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Tue, 12 May 2020 14:04:33 +1200 Subject: [PATCH 21/45] Update URLs. --- README.rst | 4 ++-- debian/control | 6 +++--- debian/copyright | 2 +- doc/source/test-of-config-with-linc.rst | 2 +- doc/source/using_with_openstack.rst | 2 +- doc/source/writing_ryu_app.rst | 6 +++--- setup.cfg | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.rst b/README.rst index 361ef599..33d02c84 100644 --- a/README.rst +++ b/README.rst @@ -20,7 +20,7 @@ Installing Ryu is quite easy:: If you prefer to install Ryu from the source code:: - % git clone git://github.com/osrg/ryu.git + % git clone https://github.com/faucetsdn/ryu.git % cd ryu; pip install . If you want to write your Ryu application, have a look at @@ -59,7 +59,7 @@ On Ubuntu(16.04 LTS or later):: Support ======= -Ryu Official site is ``_. +Ryu Official site is ``_. If you have any questions, suggestions, and patches, the mailing list is available at diff --git a/debian/control b/debian/control index 8bcbe683..0d1c1cc5 100644 --- a/debian/control +++ b/debian/control @@ -17,9 +17,9 @@ Build-Depends-Indep: python-pip, python-pbr Standards-Version: 3.9.5 -Homepage: http://osrg.github.io/ryu/ -Vcs-Git: git://github.com/osrg/ryu.git -Vcs-Browser: http://github.com/osrg/ryu +Homepage: https://ryu-sdn.org +Vcs-Git: git://github.com/faucetsdn/ryu.git +Vcs-Browser: https://github.com/faucetsdn/ryu XS-Python-Version: >= 2.6 Package: python-ryu diff --git a/debian/copyright b/debian/copyright index 63d77d3b..f05255cb 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,6 +1,6 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: ryu -Source: http://github.com/osrg/ryu +Source: http://github.com/faucetsdn/ryu Files: * Copyright: 2014 Ryu Project Team diff --git a/doc/source/test-of-config-with-linc.rst b/doc/source/test-of-config-with-linc.rst index 2ff493e5..0f8c8fa4 100644 --- a/doc/source/test-of-config-with-linc.rst +++ b/doc/source/test-of-config-with-linc.rst @@ -19,7 +19,7 @@ The test procedure * run LINC switch * run Ryu test_of_config app -For getting/installing Ryu itself, please refer to http://osrg.github.io/ryu/ +For getting/installing Ryu itself, please refer to https://ryu-sdn.org/ Install Erlang environment diff --git a/doc/source/using_with_openstack.rst b/doc/source/using_with_openstack.rst index 5e153486..13bd9a1e 100644 --- a/doc/source/using_with_openstack.rst +++ b/doc/source/using_with_openstack.rst @@ -14,7 +14,7 @@ Using Ryu Network Operating System with OpenStack as OpenFlow controller Ryu cooperates with OpenStack using Quantum Ryu plugin. The plugin is available in the official Quantum releases. -For more information, please visit http://github.com/osrg/ryu/wiki/OpenStack . +For more information, please visit https://github.com/faucetsdn/ryu/wiki/OpenStack . We described instructions of the installation / configuration of OpenStack with Ryu, and we provide pre-configured VM image to be able to easily try OpenStack with Ryu. diff --git a/doc/source/writing_ryu_app.rst b/doc/source/writing_ryu_app.rst index 7f15ed9a..a4d1830a 100644 --- a/doc/source/writing_ryu_app.rst +++ b/doc/source/writing_ryu_app.rst @@ -118,9 +118,9 @@ run a Ryu application that does something useful. Is a dumb L2 switch is too dumb? You want to implement a learning L2 switch? Move to `the next step -`_. You +`_. You can learn from the existing Ryu applications at `ryu/app -`_ directory and +`_ directory and `integrated tests -`_ +`_ directory. diff --git a/setup.cfg b/setup.cfg index 898a7c1d..c3757abb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,7 +4,7 @@ summary = Component-based Software-defined Networking Framework license = Apache License 2.0 author = Ryu project team author-email = ryu-devel@lists.sourceforge.net -home-page = http://osrg.github.io/ryu/ +home-page = https://ryu-sdn.org description-file = README.rst platform = any classifier = From 10a9f79c6a17038c00200a9b81040b7dc7fe3005 Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Tue, 12 May 2020 16:32:54 +1200 Subject: [PATCH 22/45] Update how to contribute to Ryu. --- CONTRIBUTING.rst | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 11387509..f57d074f 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -5,20 +5,8 @@ How to Get Your Change Into Ryu Submitting a change =================== -Send patches to ryu-devel@lists.sourceforge.net. Please don't use "Pull -Request" on GitHub. We expect you to send patches in "git-format-patch" -style. - -.. code-block:: bash - - # "N" means the number of commits to be included - $ git format-patch -s HEAD~N - - # To add cover (e.g., [PATCH 0/X]), specify "--cover-letter" option - $ git format-patch -s --cover-letter HEAD~N - - # You can send patches by "git send-email" command - $ git send-email --to="ryu-devel@lists.sourceforge.net" *.patch +To send patches to ryu, please make a +`pull request `_ on GitHub. Please check your changes with autopep8, pycodestyle(pep8) and running unit tests to make sure that they don't break the existing features. @@ -42,7 +30,7 @@ features (it's not a must though). Python version and libraries ============================ -* Python 2.7, 3.4, 3.5: +* Python 2.7, 3.5, 3.6, 3.7: Ryu supports multiple Python version. CI tests on Travis-CI is running on these versions. From 814c8a757a570603c3ccce1d19cbe4cea99f4c19 Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Sat, 23 May 2020 11:06:19 +1200 Subject: [PATCH 23/45] Add .readthedocs.yml. --- .readthedocs.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .readthedocs.yml diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 00000000..b0d6d443 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,11 @@ +version: 2 +build: + image: latest +python: + version: 3.6 + install: + - method: pip + path: . +sphinx: + configuration: doc/source/conf.py +formats: all From 3395daccfe49044929c3e1a8e78fb84c40332514 Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Mon, 8 Jun 2020 14:30:21 +1200 Subject: [PATCH 24/45] Deprecate using Ryu with older python versions. --- .travis.yml | 5 ----- setup.cfg | 2 -- tox.ini | 5 ----- 3 files changed, 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 712ffd12..0ce5d205 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,11 +9,6 @@ matrix: - python: 3.6 env: TOX_ENV=autopep8 - - python: 2.7 - env: TOX_ENV=pycodestyle - - python: 2.7 - env: TOX_ENV=py27 - - python: 3.5 env: TOX_ENV=py35 diff --git a/setup.cfg b/setup.cfg index c3757abb..e8afa658 100644 --- a/setup.cfg +++ b/setup.cfg @@ -13,9 +13,7 @@ classifier = Topic :: System :: Networking Natural Language :: English Programming Language :: Python - Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 - Programming Language :: Python :: 3.4 Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 diff --git a/tox.ini b/tox.ini index 65136233..25f3ba99 100644 --- a/tox.ini +++ b/tox.ini @@ -20,11 +20,6 @@ commands = commands = python ryu/tests/integrated/run_test.py -[testenv:py27] -commands = - {[testenv]commands} - {[testenv:scenario]commands} - [testenv:py36] commands = {[testenv]commands} From b6bf01a5c95da0de1e6831a3cf41243e69297854 Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Mon, 8 Jun 2020 14:30:58 +1200 Subject: [PATCH 25/45] Remove workaround for issue with older python versions. --- setup.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/setup.py b/setup.py index cf2a404d..fee79eb1 100644 --- a/setup.py +++ b/setup.py @@ -14,12 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# a bug workaround. http://bugs.python.org/issue15881 -try: - import multiprocessing -except ImportError: - pass - import setuptools import ryu.hooks From 885db99eebad050cb79ac70f752a42f60ab387da Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Tue, 12 May 2020 15:11:46 +1200 Subject: [PATCH 26/45] We don't support msgpack 1.0.0 yet. --- debian/control | 4 ++-- tools/pip-requires | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/control b/debian/control index 0d1c1cc5..200b1005 100644 --- a/debian/control +++ b/debian/control @@ -6,7 +6,7 @@ Build-Depends: debhelper (>= 9.0.0), python-all (>= 2.6), python-sphinx Build-Depends-Indep: python-eventlet, python-lxml, - python-msgpack (>= 0.3.0), + python-msgpack (>= 0.3.0), python-msgpack (< 1.0.0), python-netaddr, python-oslo.config (>= 1:1.2.0), python-paramiko, @@ -28,7 +28,7 @@ Section: python Depends: python-eventlet, python-lxml, - python-msgpack (>= 0.3.0), + python-msgpack (>= 0.3.0), python-msgpack (< 1.0.0), python-netaddr, python-oslo.config (>= 1:1.2.0), python-paramiko, diff --git a/tools/pip-requires b/tools/pip-requires index 56020060..2d59b106 100644 --- a/tools/pip-requires +++ b/tools/pip-requires @@ -2,7 +2,7 @@ # following issue. # https://github.com/eventlet/eventlet/issues/401 eventlet!=0.18.3,>=0.18.2,!=0.20.1,!=0.21.0,!=0.23.0 -msgpack>=0.3.0 # RPC library, BGP speaker(net_cntl) +msgpack>=0.3.0,<1.0.0 # RPC library, BGP speaker(net_cntl) netaddr oslo.config>=2.5.0 ovs>=2.6.0 # OVSDB From 7344c15b016401fef2947d27f07a4933a87f5cfb Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Tue, 12 May 2020 15:16:06 +1200 Subject: [PATCH 27/45] pylint --- ryu/tests/unit/lib/test_ofctl_action_match.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ryu/tests/unit/lib/test_ofctl_action_match.py b/ryu/tests/unit/lib/test_ofctl_action_match.py index 11e27f78..9e9f2e46 100644 --- a/ryu/tests/unit/lib/test_ofctl_action_match.py +++ b/ryu/tests/unit/lib/test_ofctl_action_match.py @@ -413,7 +413,7 @@ class Test_ofctl(unittest.TestCase): # without mask eq_(eth, field_value) return - elif key in['nw_src', 'nw_dst', 'arp_spa', 'arp_tpa']: + elif key in ['nw_src', 'nw_dst', 'arp_spa', 'arp_tpa']: # IPv4 address if test.ver == ofproto_v1_0.OFP_VERSION: ipv4, mask = _to_match_ip(value) From 9b002e0eece436ad72e2ec8b250620f78277c567 Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Tue, 12 May 2020 15:25:05 +1200 Subject: [PATCH 28/45] Update python versions for tox test environments. --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0ce5d205..cf263bc3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,9 +12,12 @@ matrix: - python: 3.5 env: TOX_ENV=py35 - - python: 3.7-dev + - python: 3.7 env: TOX_ENV=py37 + - python: 3.8 + env: TOX_ENV=py38 + # This is disabled because of trouble running on travis CI. # - python: pypy # env: TOX_ENV=pypy From dea688e5a68c31fcf2e059c1b65a7c0a3fbc6856 Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Tue, 12 May 2020 15:41:15 +1200 Subject: [PATCH 29/45] Upgrade to ubuntu bionic. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index cf263bc3..468b67ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ +dist: bionic + language: python matrix: From 15382e497216e6f243d9496488e50fcd014e18f2 Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Fri, 12 Jun 2020 11:23:03 +1200 Subject: [PATCH 30/45] Don't need to keep our requirements in sync with OpenStack. --- ryu/tests/unit/test_requirements.py | 85 ----------------------------- 1 file changed, 85 deletions(-) delete mode 100644 ryu/tests/unit/test_requirements.py diff --git a/ryu/tests/unit/test_requirements.py b/ryu/tests/unit/test_requirements.py deleted file mode 100644 index c842a0f0..00000000 --- a/ryu/tests/unit/test_requirements.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import logging -import os -import sys -import unittest - -import pkg_resources -from six.moves import urllib - -from nose.tools import ok_ - - -LOG = logging.getLogger(__name__) - -MOD_DIR = os.path.dirname('file://' + sys.modules[__name__].__file__) -_RYU_REQUIREMENTS_FILES = [ - '../../../tools/pip-requires', - '../../../tools/optional-requires', -] -RYU_REQUIREMENTS_FILES = [ - os.path.join(MOD_DIR, f) for f in _RYU_REQUIREMENTS_FILES] - -OPENSTACK_REQUIREMENTS_REPO = 'https://github.com/openstack/requirements' -OPENSTACK_REQUIREMENTS_URL = ( - 'https://github.com/openstack/requirements/raw/master/') -_OPENSTACK_REQUIREMENTS_FILES = [ - 'requirements.txt', - 'global-requirements.txt', -] -OPENSTACK_REQUIREMENTS_FILES = [ - urllib.parse.urljoin(OPENSTACK_REQUIREMENTS_URL, f) - for f in _OPENSTACK_REQUIREMENTS_FILES] - - -def _get_requirements(files): - requirements = {} - for f in files: - response = urllib.request.urlopen(f) - contents = response.read().decode('utf-8') - for r in pkg_resources.parse_requirements(contents): - requirements[r.name] = str(r) - - return requirements - - -OPENSTACK_REQUIREMENTS = _get_requirements(OPENSTACK_REQUIREMENTS_FILES) -RYU_REQUIREMENTS = _get_requirements(RYU_REQUIREMENTS_FILES) - - -class TestRequirements(unittest.TestCase): - """ - Test whether the requirements of Ryu has no conflict with that - of other projects. - """ - - def setUp(self): - pass - - def tearDown(self): - pass - - def test_with_openstack_requirements(self): - try: - for name, req in OPENSTACK_REQUIREMENTS.items(): - if name in RYU_REQUIREMENTS: - ok_(pkg_resources.require(req)) - except pkg_resources.VersionConflict as e: - LOG.exception( - 'Some requirements of Ryu are conflicting with that of ' - 'OpenStack project: %s', OPENSTACK_REQUIREMENTS_REPO) - raise e From 906b3a3ea5a1f2f117c0c0479e578b51a8afa0e3 Mon Sep 17 00:00:00 2001 From: Artem Abramov Date: Fri, 29 Nov 2019 14:39:37 +0300 Subject: [PATCH 31/45] Bugfix now multiple switches can connect with TLS This fixes a bug in RYU StreamServer where SSLContext was modified for each connection. Now the SSLContext of the server socket is modified only once in __init__ --- ryu/lib/hub.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/ryu/lib/hub.py b/ryu/lib/hub.py index e847f656..cac989a5 100644 --- a/ryu/lib/hub.py +++ b/ryu/lib/hub.py @@ -127,21 +127,25 @@ if HUB_TYPE == 'eventlet': self.server = eventlet.listen(listen_info) if ssl_args: - def wrap_and_handle(sock, addr): - ssl_args.setdefault('server_side', True) - if 'ssl_ctx' in ssl_args: - ctx = ssl_args.pop('ssl_ctx') - ctx.load_cert_chain(ssl_args.pop('certfile'), - ssl_args.pop('keyfile')) - if 'cert_reqs' in ssl_args: - ctx.verify_mode = ssl_args.pop('cert_reqs') - if 'ca_certs' in ssl_args: - ctx.load_verify_locations(ssl_args.pop('ca_certs')) + ssl_args.setdefault('server_side', True) + if 'ssl_ctx' in ssl_args: + ctx = ssl_args.pop('ssl_ctx') + ctx.load_cert_chain(ssl_args.pop('certfile'), + ssl_args.pop('keyfile')) + if 'cert_reqs' in ssl_args: + ctx.verify_mode = ssl_args.pop('cert_reqs') + if 'ca_certs' in ssl_args: + ctx.load_verify_locations(ssl_args.pop('ca_certs')) + + def wrap_and_handle_ctx(sock, addr): handle(ctx.wrap_socket(sock, **ssl_args), addr) - else: + + self.handle = wrap_and_handle_ctx + else: + def wrap_and_handle_ssl(sock, addr): handle(ssl.wrap_socket(sock, **ssl_args), addr) - self.handle = wrap_and_handle + self.handle = wrap_and_handle_ssl else: self.handle = handle From ddb32f678a5e1f0bbbf2cf810bdd16871abb22d9 Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Thu, 11 Jun 2020 15:01:42 +1200 Subject: [PATCH 32/45] Add workaround for Python3.7+ eventlet bug. --- ryu/controller/controller.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ryu/controller/controller.py b/ryu/controller/controller.py index b3d2d35b..1506efb4 100644 --- a/ryu/controller/controller.py +++ b/ryu/controller/controller.py @@ -30,6 +30,7 @@ from socket import TCP_NODELAY from socket import SHUT_WR from socket import timeout as SocketTimeout import ssl +import sys from ryu import cfg from ryu.lib import hub @@ -169,6 +170,12 @@ class OpenFlowController(object): # anything less than python 2.7.9 supports only TLSv1 # or less, thus we choose TLSv1 ssl_args = {'ssl_version': ssl.PROTOCOL_TLSv1} + elif sys.version_info >= (3, 7,): + # On Python3.7+ we can't wrap an SSLContext due to this bug: + # https://github.com/eventlet/eventlet/issues/526 + # Lets assume the system has a new enough OpenSSL that + # SSL is fully disabled. + ssl_args = {'ssl_version': ssl.PROTOCOL_TLSv1} else: # from 2.7.9 and versions 3.4+ ssl context creation is # supported. Protocol_TLS from 2.7.13 and from 3.5.3 From 7559befd58332544871cf62851c110c00e4ff1c9 Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Thu, 11 Jun 2020 16:42:45 +1200 Subject: [PATCH 33/45] Allow user to set cipher list. --- ryu/controller/controller.py | 4 ++++ ryu/tests/unit/controller/test_controller.py | 1 + 2 files changed, 5 insertions(+) diff --git a/ryu/controller/controller.py b/ryu/controller/controller.py index 1506efb4..d79f290a 100644 --- a/ryu/controller/controller.py +++ b/ryu/controller/controller.py @@ -68,6 +68,7 @@ CONF.register_cli_opts([ cfg.StrOpt('ctl-privkey', default=None, help='controller private key'), cfg.StrOpt('ctl-cert', default=None, help='controller certificate'), cfg.StrOpt('ca-certs', default=None, help='CA certificates'), + cfg.StrOpt('ciphers', default=None, help='list of ciphers to enable'), cfg.ListOpt('ofp-switch-address-list', item_type=str, default=[], help='list of IP address and port pairs (default empty). ' 'e.g., "127.0.0.1:6653,[::1]:6653"'), @@ -189,6 +190,9 @@ class OpenFlowController(object): # Restrict non-safe versions ssl_args['ssl_ctx'].options |= ssl.OP_NO_SSLv3 | ssl.OP_NO_SSLv2 + if CONF.ciphers is not None: + ssl_args['ciphers'] = CONF.ciphers + if CONF.ca_certs is not None: server = StreamServer((CONF.ofp_listen_host, ofp_ssl_listen_port), diff --git a/ryu/tests/unit/controller/test_controller.py b/ryu/tests/unit/controller/test_controller.py index 45c659c9..ce09ac7e 100644 --- a/ryu/tests/unit/controller/test_controller.py +++ b/ryu/tests/unit/controller/test_controller.py @@ -191,6 +191,7 @@ class TestOpenFlowController(unittest.TestCase): conf_mock.ofp_ssl_listen_port = port conf_mock.ofp_listen_host = "127.0.0.1" conf_mock.ca_certs = None + conf_mock.ciphers = None conf_mock.ctl_cert = os.path.join(this_dir, 'cert.crt') conf_mock.ctl_privkey = os.path.join(this_dir, 'cert.key') c = controller.OpenFlowController() From f1b46fdebee973ac9bd75fe02bae47a9f5004584 Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Fri, 12 Jun 2020 15:18:59 +1200 Subject: [PATCH 34/45] Add .stickler.yml. --- .stickler.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .stickler.yml diff --git a/.stickler.yml b/.stickler.yml new file mode 100644 index 00000000..7fcbba89 --- /dev/null +++ b/.stickler.yml @@ -0,0 +1,9 @@ +--- +linters: + flake8: + python: 3 + max-line-length: 120 + pep8: + python: 3 + max-line-length: 120 + py3k: From ca597a5e0976c7d51851344010a3b91dd4d58641 Mon Sep 17 00:00:00 2001 From: Michael Haro Date: Mon, 20 Jul 2020 07:20:34 -0700 Subject: [PATCH 35/45] Add support for the MTU ND option. --- ryu/lib/packet/icmpv6.py | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/ryu/lib/packet/icmpv6.py b/ryu/lib/packet/icmpv6.py index a391c087..0c228382 100644 --- a/ryu/lib/packet/icmpv6.py +++ b/ryu/lib/packet/icmpv6.py @@ -623,6 +623,50 @@ class nd_option_pi(nd_option): return six.binary_type(hdr) +@nd_router_advert.register_nd_option_type +class nd_option_mtu(nd_option): + """ICMPv6 sub encoder/decoder class for Neighbor discovery + MTU Option. (RFC 4861) + + This is used with ryu.lib.packet.icmpv6.nd_router_advert. + + An instance has the following attributes at least. + Most of them are same to the on-wire counterparts but in host byte order. + __init__ takes the corresponding args in this order. + + .. tabularcolumns:: |l|p{35em}| + + ============== ==================== + Attribute Description + ============== ==================== + mtu MTU. + ============== ==================== + """ + + _PACK_STR = '!BBHI' + _LEN = struct.calcsize(_PACK_STR) + _OPTION_LEN = _LEN // 8 + + @classmethod + def option_type(cls): + return ND_OPTION_MTU + + def __init__(self, mtu=1500): + super(nd_option_mtu, self).__init__(self.option_type(), 0) + self.mtu = mtu + + @classmethod + def parser(cls, buf, offset): + (_, _, _, mtu) = struct.unpack_from(cls._PACK_STR, buf, offset) + msg = cls(mtu) + return msg + + def serialize(self): + buf = bytearray(struct.pack( + self._PACK_STR, self.option_type(), self._OPTION_LEN, 0, self.mtu)) + return six.binary_type(buf) + + @icmpv6.register_icmpv6_type(ICMPV6_ECHO_REPLY, ICMPV6_ECHO_REQUEST) class echo(_ICMPv6Payload): """ICMPv6 sub encoder/decoder class for Echo Request and Echo Reply From 830b49798fc07b63f7888bdcd9dcdc63a663d8bb Mon Sep 17 00:00:00 2001 From: Michael Haro Date: Mon, 20 Jul 2020 07:43:35 -0700 Subject: [PATCH 36/45] Resolve a syntax warning --- ryu/lib/packet/cfm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ryu/lib/packet/cfm.py b/ryu/lib/packet/cfm.py index 0e8c2cf1..cbf9999a 100644 --- a/ryu/lib/packet/cfm.py +++ b/ryu/lib/packet/cfm.py @@ -268,7 +268,7 @@ class cc_message(operation): self._opcode = CFM_CC_MESSAGE assert rdi in [0, 1] self.rdi = rdi - assert interval is not 0 + assert interval != 0 self.interval = interval self.seq_num = seq_num assert 1 <= mep_id <= 8191 From 8533f7ef3fd5eabe28726dd6f35578e799f9926f Mon Sep 17 00:00:00 2001 From: cglewis Date: Sun, 17 Jan 2021 12:39:21 -0800 Subject: [PATCH 37/45] fix docker tests and print output for python3 --- ryu/tests/unit/lib/ovs/test_vsctl.py | 6 +++--- tools/install_venv.py | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ryu/tests/unit/lib/ovs/test_vsctl.py b/ryu/tests/unit/lib/ovs/test_vsctl.py index 84698eec..92e00f62 100644 --- a/ryu/tests/unit/lib/ovs/test_vsctl.py +++ b/ryu/tests/unit/lib/ovs/test_vsctl.py @@ -35,7 +35,7 @@ LOG = logging.getLogger(__name__) DOCKER_IMAGE_MININET = 'osrg/ryu-book' OVSDB_MANAGER_ADDR = 'ptcp:6640' -OVSDB_SWITCH_ADDR = 'tcp:%s:6640' +OVSDB_SWITCH_ADDR = 'tcp:0.0.0.0:6640' def setUpModule(): @@ -93,7 +93,7 @@ class TestVSCtl(unittest.TestCase): @classmethod def _docker_run(cls, image): - return _run('docker run --privileged -t -d %s' % image)[0] + return _run('docker run --privileged -t -d -p 6640:6640 %s' % image)[0] @classmethod def _docker_stop(cls, container): @@ -124,7 +124,7 @@ class TestVSCtl(unittest.TestCase): @classmethod def _set_up_vsctl(cls): - cls.vsctl = vsctl.VSCtl(OVSDB_SWITCH_ADDR % cls.container_mn_ip) + cls.vsctl = vsctl.VSCtl(OVSDB_SWITCH_ADDR) @classmethod def setUpClass(cls): diff --git a/tools/install_venv.py b/tools/install_venv.py index 29639801..13a5bc17 100644 --- a/tools/install_venv.py +++ b/tools/install_venv.py @@ -70,29 +70,29 @@ def check_dependencies(): if not HAS_VIRTUALENV: raise Exception('Virtualenv not found. ' + \ 'Try installing python-virtualenv') - print 'done.' + print('done.') # pylint: disable=print-statement def create_virtualenv(venv=VENV, install_pip=False): """Creates the virtual environment and installs PIP only into the virtual environment """ - print 'Creating venv...', + print('Creating venv...') # pylint: disable=print-statement install = ['virtualenv', '-q', venv] run_command(install) - print 'done.' - print 'Installing pip in virtualenv...', + print('done.') # pylint: disable=print-statement + print('Installing pip in virtualenv...') # pylint: disable=print-statement if install_pip and \ not run_command(['tools/with_venv.sh', 'easy_install', 'pip>1.0']): die("Failed to install pip.") - print 'done.' + print('done.') # pylint: disable=print-statement def install_dependencies(venv=VENV): - print 'Installing dependencies with pip (this can take a while)...' + print('Installing dependencies with pip (this can take a while)...') # pylint: disable=print-statement run_command(['tools/with_venv.sh', 'pip', 'install', '-r', PIP_REQUIRES], redirect_output=False) run_command(['tools/with_venv.sh', 'pip', 'install', '-r', @@ -126,7 +126,7 @@ def print_help(): Also, make test will automatically use the virtualenv. """ - print help + print(help) # pylint: disable=print-statement def main(argv): From 7fc22c00e18deb762227c8f41a60280ffbb47015 Mon Sep 17 00:00:00 2001 From: cglewis Date: Mon, 18 Jan 2021 09:58:44 -0800 Subject: [PATCH 38/45] add github actions for tox tests --- .github/workflows/tests-unit.yml | 25 +++++++++++++++++++++++++ tox.ini | 9 ++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/tests-unit.yml diff --git a/.github/workflows/tests-unit.yml b/.github/workflows/tests-unit.yml new file mode 100644 index 00000000..4fa0b01d --- /dev/null +++ b/.github/workflows/tests-unit.yml @@ -0,0 +1,25 @@ +name: Unit tests + +on: [push, pull_request] + +jobs: + unit-tests: + name: Unit tests + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.5, 3.6, 3.7, 3.8] + steps: + - name: Checkout repo + uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox tox-gh-actions coveralls + bash ryu/tests/integrated/common/install_docker_test_pkg_for_travis.sh + - name: Test with tox + run: NOSE_VERBOSE=0 tox diff --git a/tox.ini b/tox.ini index 25f3ba99..0af2110f 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,12 @@ [tox] -envlist = py27,py34,py35,py36,py37,pypy,pycodestyle,autopep8 +envlist = py35,py36,py37,py38,pypy,pycodestyle,autopep8 + +[gh-actions] +python = + 3.5: py35 + 3.6: py36, pycodestyle, autopep8 + 3.7: py37 + 3.8: py38 [testenv] deps = From 0e6ddebe75d754e054b6f49da8729a86303ce795 Mon Sep 17 00:00:00 2001 From: cglewis Date: Mon, 18 Jan 2021 13:06:05 -0800 Subject: [PATCH 39/45] remove travis, move to github actions --- .github/workflows/tests-unit.yml | 2 +- .travis.yml | 40 ------------------- CONTRIBUTING.rst | 4 +- ...all_docker_test_pkg_for_github_actions.sh} | 0 4 files changed, 3 insertions(+), 43 deletions(-) delete mode 100644 .travis.yml rename ryu/tests/integrated/common/{install_docker_test_pkg_for_travis.sh => install_docker_test_pkg_for_github_actions.sh} (100%) diff --git a/.github/workflows/tests-unit.yml b/.github/workflows/tests-unit.yml index 4fa0b01d..0e7a1a05 100644 --- a/.github/workflows/tests-unit.yml +++ b/.github/workflows/tests-unit.yml @@ -20,6 +20,6 @@ jobs: run: | python -m pip install --upgrade pip pip install tox tox-gh-actions coveralls - bash ryu/tests/integrated/common/install_docker_test_pkg_for_travis.sh + bash ryu/tests/integrated/common/install_docker_test_pkg_for_github_actions.sh - name: Test with tox run: NOSE_VERBOSE=0 tox diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 468b67ef..00000000 --- a/.travis.yml +++ /dev/null @@ -1,40 +0,0 @@ -dist: bionic - -language: python - -matrix: - include: - - python: 3.6 - env: TOX_ENV=pycodestyle - - python: 3.6 - env: TOX_ENV=py36 - - python: 3.6 - env: TOX_ENV=autopep8 - - - python: 3.5 - env: TOX_ENV=py35 - - - python: 3.7 - env: TOX_ENV=py37 - - - python: 3.8 - env: TOX_ENV=py38 - -# This is disabled because of trouble running on travis CI. -# - python: pypy -# env: TOX_ENV=pypy - -services: - - docker - -sudo: required # Required to enable Docker service - -install: - - pip install tox coveralls - - bash ryu/tests/integrated/common/install_docker_test_pkg_for_travis.sh - -script: - - NOSE_VERBOSE=0 tox -e $TOX_ENV - -after_success: - - coveralls diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index f57d074f..c501f909 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -30,9 +30,9 @@ features (it's not a must though). Python version and libraries ============================ -* Python 2.7, 3.5, 3.6, 3.7: +* Python 3.5, 3.6, 3.7, 3.8: - Ryu supports multiple Python version. CI tests on Travis-CI is running + Ryu supports multiple Python versions. CI tests on GitHub Actions is running on these versions. * standard library + widely used library: diff --git a/ryu/tests/integrated/common/install_docker_test_pkg_for_travis.sh b/ryu/tests/integrated/common/install_docker_test_pkg_for_github_actions.sh similarity index 100% rename from ryu/tests/integrated/common/install_docker_test_pkg_for_travis.sh rename to ryu/tests/integrated/common/install_docker_test_pkg_for_github_actions.sh From 0a1e1e81cf3258514467fcdc93998001077267b5 Mon Sep 17 00:00:00 2001 From: Benjamin Beasley Date: Tue, 29 Dec 2020 13:20:48 -0500 Subject: [PATCH 40/45] Bump minimum msgpack verson to 0.4.0, since ryu/lib/rpc.py uses the use_bin_type option to msgpack.Packer --- debian/control | 4 ++-- tools/pip-requires | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/control b/debian/control index 200b1005..42976b81 100644 --- a/debian/control +++ b/debian/control @@ -6,7 +6,7 @@ Build-Depends: debhelper (>= 9.0.0), python-all (>= 2.6), python-sphinx Build-Depends-Indep: python-eventlet, python-lxml, - python-msgpack (>= 0.3.0), python-msgpack (< 1.0.0), + python-msgpack (>= 0.4.0), python-msgpack (< 1.0.0), python-netaddr, python-oslo.config (>= 1:1.2.0), python-paramiko, @@ -28,7 +28,7 @@ Section: python Depends: python-eventlet, python-lxml, - python-msgpack (>= 0.3.0), python-msgpack (< 1.0.0), + python-msgpack (>= 0.4.0), python-msgpack (< 1.0.0), python-netaddr, python-oslo.config (>= 1:1.2.0), python-paramiko, diff --git a/tools/pip-requires b/tools/pip-requires index 2d59b106..cc394abb 100644 --- a/tools/pip-requires +++ b/tools/pip-requires @@ -2,7 +2,7 @@ # following issue. # https://github.com/eventlet/eventlet/issues/401 eventlet!=0.18.3,>=0.18.2,!=0.20.1,!=0.21.0,!=0.23.0 -msgpack>=0.3.0,<1.0.0 # RPC library, BGP speaker(net_cntl) +msgpack>=0.4.0,<1.0.0 # RPC library, BGP speaker(net_cntl) netaddr oslo.config>=2.5.0 ovs>=2.6.0 # OVSDB From 8990ed47edc82fb2b7600bf37029d6f770ef1a41 Mon Sep 17 00:00:00 2001 From: Benjamin Beasley Date: Tue, 29 Dec 2020 14:42:30 -0500 Subject: [PATCH 41/45] Enforce new msgpack format (use_bin_type=True) in ryu.services.protocols.bgp.net_ctrl.RpcSession; this option is already used in ryu.lib.rpc.MessageEncoder --- ryu/services/protocols/bgp/net_ctrl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ryu/services/protocols/bgp/net_ctrl.py b/ryu/services/protocols/bgp/net_ctrl.py index 92a8e71e..b79d1265 100644 --- a/ryu/services/protocols/bgp/net_ctrl.py +++ b/ryu/services/protocols/bgp/net_ctrl.py @@ -101,7 +101,7 @@ class RpcSession(Activity): def __init__(self, sock, outgoing_msg_sink_iter): self.peer_name = str(sock.getpeername()) super(RpcSession, self).__init__(self.NAME_FMT % self.peer_name) - self._packer = msgpack.Packer(encoding='utf-8') + self._packer = msgpack.Packer(encoding='utf-8', use_bin_type=True) self._unpacker = msgpack.Unpacker(encoding='utf-8') self._next_msgid = 0 self._socket = sock From aa10cac1db026c8c77354f257300440b55266c9c Mon Sep 17 00:00:00 2001 From: Benjamin Beasley Date: Wed, 30 Dec 2020 09:59:13 -0500 Subject: [PATCH 42/45] Add msgpack 1.0 support; use version testing to preserve compatibility with older versions --- debian/control | 4 ++-- ryu/lib/rpc.py | 12 ++++++++++-- ryu/services/protocols/bgp/net_ctrl.py | 12 ++++++++++-- tools/pip-requires | 2 +- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/debian/control b/debian/control index 42976b81..fd5af74a 100644 --- a/debian/control +++ b/debian/control @@ -6,7 +6,7 @@ Build-Depends: debhelper (>= 9.0.0), python-all (>= 2.6), python-sphinx Build-Depends-Indep: python-eventlet, python-lxml, - python-msgpack (>= 0.4.0), python-msgpack (< 1.0.0), + python-msgpack (>= 0.4.0), python-netaddr, python-oslo.config (>= 1:1.2.0), python-paramiko, @@ -28,7 +28,7 @@ Section: python Depends: python-eventlet, python-lxml, - python-msgpack (>= 0.4.0), python-msgpack (< 1.0.0), + python-msgpack (>= 0.4.0), python-netaddr, python-oslo.config (>= 1:1.2.0), python-paramiko, diff --git a/ryu/lib/rpc.py b/ryu/lib/rpc.py index 7db0ebeb..f74f8846 100644 --- a/ryu/lib/rpc.py +++ b/ryu/lib/rpc.py @@ -40,8 +40,16 @@ class MessageEncoder(object): def __init__(self): super(MessageEncoder, self).__init__() - self._packer = msgpack.Packer(encoding='utf-8', use_bin_type=True) - self._unpacker = msgpack.Unpacker(encoding='utf-8') + if msgpack.version >= (1, 0, 0): + self._packer = msgpack.Packer() + # The strict_map_key=False option is required to use int keys in + # maps; it is disabled by default to prevent hash collision denial + # of service attacks (hashdos) in scenarios where an attacker can + # control the keys to be hashed. + self._unpacker = msgpack.Unpacker(strict_map_key=False) + else: + self._packer = msgpack.Packer(encoding='utf-8', use_bin_type=True) + self._unpacker = msgpack.Unpacker(encoding='utf-8') self._next_msgid = 0 def _create_msgid(self): diff --git a/ryu/services/protocols/bgp/net_ctrl.py b/ryu/services/protocols/bgp/net_ctrl.py index b79d1265..5c79d3f8 100644 --- a/ryu/services/protocols/bgp/net_ctrl.py +++ b/ryu/services/protocols/bgp/net_ctrl.py @@ -101,8 +101,16 @@ class RpcSession(Activity): def __init__(self, sock, outgoing_msg_sink_iter): self.peer_name = str(sock.getpeername()) super(RpcSession, self).__init__(self.NAME_FMT % self.peer_name) - self._packer = msgpack.Packer(encoding='utf-8', use_bin_type=True) - self._unpacker = msgpack.Unpacker(encoding='utf-8') + if msgpack.version >= (1, 0, 0): + self._packer = msgpack.Packer() + # The strict_map_key=False option is required to use int keys in + # maps; it is disabled by default to prevent hash collision denial + # of service attacks (hashdos) in scenarios where an attacker can + # control the keys to be hashed. + self._unpacker = msgpack.Unpacker(strict_map_key=False) + else: + self._packer = msgpack.Packer(encoding='utf-8', use_bin_type=True) + self._unpacker = msgpack.Unpacker(encoding='utf-8') self._next_msgid = 0 self._socket = sock self._outgoing_msg_sink_iter = outgoing_msg_sink_iter diff --git a/tools/pip-requires b/tools/pip-requires index cc394abb..6de3cfc2 100644 --- a/tools/pip-requires +++ b/tools/pip-requires @@ -2,7 +2,7 @@ # following issue. # https://github.com/eventlet/eventlet/issues/401 eventlet!=0.18.3,>=0.18.2,!=0.20.1,!=0.21.0,!=0.23.0 -msgpack>=0.4.0,<1.0.0 # RPC library, BGP speaker(net_cntl) +msgpack>=0.4.0 # RPC library, BGP speaker(net_cntl) netaddr oslo.config>=2.5.0 ovs>=2.6.0 # OVSDB From 8740dd97e46ca4cf989e089fa612a1369f059a8d Mon Sep 17 00:00:00 2001 From: cglewis Date: Tue, 19 Jan 2021 17:59:31 -0800 Subject: [PATCH 43/45] add renovate --- .renovaterc.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .renovaterc.json diff --git a/.renovaterc.json b/.renovaterc.json new file mode 100644 index 00000000..e1e004b7 --- /dev/null +++ b/.renovaterc.json @@ -0,0 +1,15 @@ +{ + "separateMajorMinor": false, + "schedule": [ + "after 10pm every weekday", + "before 5am every weekday", + "every weekend" + ], + "timezone": "Pacific/Auckland", + "extends": [ + "config:base", + ":prHourlyLimit1", + ":preserveSemverRanges", + "docker:enableMajor" + ] +} From afa2f835596761d4633e9eccce0c79d56e960553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20K=C3=A4mmerling?= Date: Mon, 21 Dec 2020 11:47:04 +0100 Subject: [PATCH 44/45] Add Support for Python 3.9 --- .github/workflows/tests-unit.yml | 2 +- CONTRIBUTING.rst | 2 +- setup.cfg | 2 ++ tox.ini | 3 ++- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests-unit.yml b/.github/workflows/tests-unit.yml index 0e7a1a05..0395e44f 100644 --- a/.github/workflows/tests-unit.yml +++ b/.github/workflows/tests-unit.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.5, 3.6, 3.7, 3.8] + python-version: [3.5, 3.6, 3.7, 3.8, 3.9] steps: - name: Checkout repo uses: actions/checkout@v2 diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index c501f909..c2ce5ca3 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -30,7 +30,7 @@ features (it's not a must though). Python version and libraries ============================ -* Python 3.5, 3.6, 3.7, 3.8: +* Python 3.5, 3.6, 3.7, 3.8, 3.9: Ryu supports multiple Python versions. CI tests on GitHub Actions is running on these versions. diff --git a/setup.cfg b/setup.cfg index e8afa658..b3716c1c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -17,6 +17,8 @@ classifier = Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 Operating System :: Unix keywords = openflow diff --git a/tox.ini b/tox.ini index 0af2110f..37b95397 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py35,py36,py37,py38,pypy,pycodestyle,autopep8 +envlist = py35,py36,py37,py38,py39,pypy,pycodestyle,autopep8 [gh-actions] python = @@ -7,6 +7,7 @@ python = 3.6: py36, pycodestyle, autopep8 3.7: py37 3.8: py38 + 3.9: py39 [testenv] deps = From ea4112f39321d8e776f933b067fe9bb683697aa0 Mon Sep 17 00:00:00 2001 From: cglewis Date: Wed, 20 Jan 2021 10:40:50 -0800 Subject: [PATCH 45/45] revert #100, use latest eventlet --- ryu/controller/controller.py | 7 ------- tools/pip-requires | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/ryu/controller/controller.py b/ryu/controller/controller.py index d79f290a..698e375e 100644 --- a/ryu/controller/controller.py +++ b/ryu/controller/controller.py @@ -30,7 +30,6 @@ from socket import TCP_NODELAY from socket import SHUT_WR from socket import timeout as SocketTimeout import ssl -import sys from ryu import cfg from ryu.lib import hub @@ -171,12 +170,6 @@ class OpenFlowController(object): # anything less than python 2.7.9 supports only TLSv1 # or less, thus we choose TLSv1 ssl_args = {'ssl_version': ssl.PROTOCOL_TLSv1} - elif sys.version_info >= (3, 7,): - # On Python3.7+ we can't wrap an SSLContext due to this bug: - # https://github.com/eventlet/eventlet/issues/526 - # Lets assume the system has a new enough OpenSSL that - # SSL is fully disabled. - ssl_args = {'ssl_version': ssl.PROTOCOL_TLSv1} else: # from 2.7.9 and versions 3.4+ ssl context creation is # supported. Protocol_TLS from 2.7.13 and from 3.5.3 diff --git a/tools/pip-requires b/tools/pip-requires index 2d59b106..e6c408f5 100644 --- a/tools/pip-requires +++ b/tools/pip-requires @@ -1,7 +1,7 @@ # NOTE: OpenStack avoids some versions of eventlet, because of the # following issue. # https://github.com/eventlet/eventlet/issues/401 -eventlet!=0.18.3,>=0.18.2,!=0.20.1,!=0.21.0,!=0.23.0 +eventlet==0.30.0 msgpack>=0.3.0,<1.0.0 # RPC library, BGP speaker(net_cntl) netaddr oslo.config>=2.5.0