From d0cd93c1a04712544c83b45765b3c3f5bd2f9433 Mon Sep 17 00:00:00 2001 From: Dennis Date: Thu, 18 Jan 2018 10:33:22 -0800 Subject: [PATCH 01/36] 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 62b4c07464c67227fd35026291c90aa006072841 Mon Sep 17 00:00:00 2001 From: Benjamin Villain Date: Fri, 28 Sep 2018 14:25:00 +1000 Subject: [PATCH 02/36] Adding support for RFC8227 withdraw label According to RFC8227, many vendors don't properly implement RFC3107 related to withdraw label. Indeed, it happens that a speaker sends a label of 0x000000 in place of 0x800000 to signal a route withdrawal. As a result, the parser fails to parse the message since it doesn't stop at the withdraw label and tries to parse more label than there is. This commit fixes this by considering both 0x800000 and 0x000000 as withdraw labels. --- 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 faffcb80d429d6aee7d8ad31d428ab8c952767ec Mon Sep 17 00:00:00 2001 From: Diego Rossi Mafioletti Date: Thu, 11 Apr 2019 07:09:42 -0300 Subject: [PATCH 03/36] 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 d1b1b471e7e202e9955d230de01aae0702fcdb7c Mon Sep 17 00:00:00 2001 From: Benjamin Villain Date: Thu, 19 Sep 2019 17:14:37 +1000 Subject: [PATCH 04/36] 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 c565ec6f77e051e36522932e03ceb410cfee8c1e Mon Sep 17 00:00:00 2001 From: MrCocoaCat Date: Fri, 20 Mar 2020 18:34:30 +0800 Subject: [PATCH 05/36] Update bridge.py Sometimes you don't know 'datapath_id', you need to initialize the class with 'br_name' --- ryu/lib/ovs/bridge.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ryu/lib/ovs/bridge.py b/ryu/lib/ovs/bridge.py index f86e9ae0..1bfb9c07 100644 --- a/ryu/lib/ovs/bridge.py +++ b/ryu/lib/ovs/bridge.py @@ -114,7 +114,7 @@ class OVSBridge(object): """ def __init__(self, CONF, datapath_id, ovsdb_addr, timeout=None, - exception=None): + exception=None, br_name=None): super(OVSBridge, self).__init__() self.datapath_id = datapath_id self.ovsdb_addr = ovsdb_addr @@ -122,7 +122,7 @@ class OVSBridge(object): self.timeout = timeout or CONF.ovsdb_timeout self.exception = exception - self.br_name = None + self.br_name = br_name def run_command(self, commands): """ From 3395daccfe49044929c3e1a8e78fb84c40332514 Mon Sep 17 00:00:00 2001 From: Brad Cowie Date: Mon, 8 Jun 2020 14:30:21 +1200 Subject: [PATCH 06/36] 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 07/36] 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 08/36] 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 09/36] 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 10/36] 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 11/36] 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 12/36] 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 13/36] 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 14/36] 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 15/36] 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 16/36] 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 20c0ececebb4e62f1b00f456de2d92d6a38dbbe3 Mon Sep 17 00:00:00 2001 From: Santiago Rodriguez Date: Sun, 14 Jun 2020 16:13:22 +0100 Subject: [PATCH 17/36] doc: Consider null buffer_id in first example If the switch does not buffer the packet (like when using mininet), the example does not work. For such cases, include the packet contents in OFPPacketOut --- doc/source/writing_ryu_app.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/source/writing_ryu_app.rst b/doc/source/writing_ryu_app.rst index a4d1830a..c2f71526 100644 --- a/doc/source/writing_ryu_app.rst +++ b/doc/source/writing_ryu_app.rst @@ -67,11 +67,16 @@ the ports. dp = msg.datapath ofp = dp.ofproto ofp_parser = dp.ofproto_parser - + actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD)] + + data = None + if msg.buffer_id == ofp.OFP_NO_BUFFER + data = msg.data + out = ofp_parser.OFPPacketOut( datapath=dp, buffer_id=msg.buffer_id, in_port=msg.in_port, - actions=actions) + actions=actions, data = data) dp.send_msg(out) From 0e0f66e119e4a8b69e731fa89261185473b505d3 Mon Sep 17 00:00:00 2001 From: shinkasbe Date: Tue, 16 Jun 2020 10:14:42 +0100 Subject: [PATCH 18/36] doc: Fix typo on example --- 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 c2f71526..79d7528e 100644 --- a/doc/source/writing_ryu_app.rst +++ b/doc/source/writing_ryu_app.rst @@ -71,7 +71,7 @@ the ports. actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD)] data = None - if msg.buffer_id == ofp.OFP_NO_BUFFER + if msg.buffer_id == ofp.OFP_NO_BUFFER: data = msg.data out = ofp_parser.OFPPacketOut( From ca597a5e0976c7d51851344010a3b91dd4d58641 Mon Sep 17 00:00:00 2001 From: Michael Haro Date: Mon, 20 Jul 2020 07:20:34 -0700 Subject: [PATCH 19/36] 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 20/36] 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 21/36] 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 22/36] 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 23/36] 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 24/36] 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 25/36] 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 26/36] 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 27/36] 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 28/36] 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 29/36] 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 From 62e1ec69981e16cc33695068dab2f6340645f8ce Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Wed, 10 Feb 2021 10:33:28 +1300 Subject: [PATCH 30/36] 0.30.1 --- tools/pip-requires | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pip-requires b/tools/pip-requires index b2ecef8a..719ee05f 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.30.0 +eventlet==0.30.1 msgpack>=0.4.0 # RPC library, BGP speaker(net_cntl) netaddr oslo.config>=2.5.0 From a004f57c1fb4ba401fb42d0cd86db6ce3e576ac1 Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Mon, 22 Feb 2021 10:52:50 +1300 Subject: [PATCH 31/36] pin pip to 20.3.4. --- .github/workflows/tests-unit.yml | 2 +- pip-requirements.txt | 1 + tools/pip-requires | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 pip-requirements.txt diff --git a/.github/workflows/tests-unit.yml b/.github/workflows/tests-unit.yml index 0395e44f..866f151f 100644 --- a/.github/workflows/tests-unit.yml +++ b/.github/workflows/tests-unit.yml @@ -18,7 +18,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | - python -m pip install --upgrade pip + python -m pip install --upgrade -r pip-requirements.txt pip install tox tox-gh-actions coveralls bash ryu/tests/integrated/common/install_docker_test_pkg_for_github_actions.sh - name: Test with tox diff --git a/pip-requirements.txt b/pip-requirements.txt new file mode 100644 index 00000000..a9a3cb75 --- /dev/null +++ b/pip-requirements.txt @@ -0,0 +1 @@ +pip==20.3.4 diff --git a/tools/pip-requires b/tools/pip-requires index 719ee05f..c0ded86e 100644 --- a/tools/pip-requires +++ b/tools/pip-requires @@ -1,3 +1,4 @@ +-r ../pip-requirements.txt # NOTE: OpenStack avoids some versions of eventlet, because of the # following issue. # https://github.com/eventlet/eventlet/issues/401 From bff06a2b05cf62e8f7f896157a450e43b2830f6b Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Wed, 26 May 2021 00:02:52 +0000 Subject: [PATCH 32/36] upgrade tinyrpc to 1.0.4. --- tools/pip-requires | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pip-requires b/tools/pip-requires index c0ded86e..86bf1220 100644 --- a/tools/pip-requires +++ b/tools/pip-requires @@ -9,5 +9,5 @@ oslo.config>=2.5.0 ovs>=2.6.0 # OVSDB routes # wsgi six>=1.4.0 -tinyrpc==0.9.4 # RPC library, BGP speaker(net_cntl) +tinyrpc==1.0.4 # RPC library, BGP speaker(net_cntl) webob>=1.2 # wsgi From dfe583bd837902af0276b31eedbc340adc695815 Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Tue, 1 Jun 2021 08:02:07 +1200 Subject: [PATCH 33/36] Upgrade eventlet. --- ryu/app/wsgi.py | 11 +++++++++-- tools/pip-requires | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/ryu/app/wsgi.py b/ryu/app/wsgi.py index 0b98df94..9c171e4f 100644 --- a/ryu/app/wsgi.py +++ b/ryu/app/wsgi.py @@ -108,8 +108,15 @@ class WebSocketRegistrationWrapper(object): class _AlreadyHandledResponse(Response): # XXX: Eventlet API should not be used directly. - from eventlet.wsgi import ALREADY_HANDLED - _ALREADY_HANDLED = ALREADY_HANDLED + # https://github.com/benoitc/gunicorn/pull/2581 + from packaging import version + import eventlet + if version.parse(eventlet.__version__) >= version.parse("0.30.3"): + import eventlet.wsgi + _ALREADY_HANDLED = getattr(eventlet.wsgi, "ALREADY_HANDLED", None) + else: + from eventlet.wsgi import ALREADY_HANDLED + _ALREADY_HANDLED = ALREADY_HANDLED def __call__(self, environ, start_response): return self._ALREADY_HANDLED diff --git a/tools/pip-requires b/tools/pip-requires index 86bf1220..02f867ab 100644 --- a/tools/pip-requires +++ b/tools/pip-requires @@ -2,11 +2,12 @@ # NOTE: OpenStack avoids some versions of eventlet, because of the # following issue. # https://github.com/eventlet/eventlet/issues/401 -eventlet==0.30.1 +eventlet==0.31.0 msgpack>=0.4.0 # RPC library, BGP speaker(net_cntl) netaddr oslo.config>=2.5.0 ovs>=2.6.0 # OVSDB +packaging==20.9 routes # wsgi six>=1.4.0 tinyrpc==1.0.4 # RPC library, BGP speaker(net_cntl) From 8b41507c2c1e96ccb4e28bf2709b18a6bde2a547 Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Thu, 3 Jun 2021 00:44:17 +0000 Subject: [PATCH 34/36] Enable bare minimum pytype + GHA (no ryu code changes). Exclusions/ignored errors can be incrementally removed, to manage diff size and risk. --- setup.cfg | 11 +++++++++++ tools/test-requires | 1 + tox.ini | 12 ++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/setup.cfg b/setup.cfg index b3716c1c..96208014 100644 --- a/setup.cfg +++ b/setup.cfg @@ -55,3 +55,14 @@ setup-hooks = console_scripts = ryu-manager = ryu.cmd.manager:main ryu = ryu.cmd.ryu_base:main + +[pytype] +inputs = + ryu/controller/ +disable = + attribute-error + import-error + key-error + module-attr +keep-going = + 1 diff --git a/tools/test-requires b/tools/test-requires index e0503381..dfef2215 100644 --- a/tools/test-requires +++ b/tools/test-requires @@ -4,4 +4,5 @@ mock nose pycodestyle pylint +pytype formencode diff --git a/tox.ini b/tox.ini index 37b95397..04ebe1c1 100644 --- a/tox.ini +++ b/tox.ini @@ -1,10 +1,10 @@ [tox] -envlist = py35,py36,py37,py38,py39,pypy,pycodestyle,autopep8 +envlist = py35,py36,py37,py38,py39,pypy,pycodestyle,autopep8,pytype [gh-actions] python = 3.5: py35 - 3.6: py36, pycodestyle, autopep8 + 3.6: py36, pycodestyle, autopep8, pytype 3.7: py37 3.8: py38 3.9: py39 @@ -53,6 +53,14 @@ deps = commands = bash -c 'test -z "$(autopep8 --recursive --diff ryu/)"' +[testenv:pytype] +deps = + -U + --no-cache-dir + pytype +commands = + pytype --jobs 2 + [pycodestyle] exclude = pbr-*,.venv,.tox,.git,doc,dist,tools,vcsversion.py,.pyc,ryu/contrib # W503: line break before binary operator From 98d4913d324c7fb8d15dab54dd5fd006d2c1efce Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Sun, 6 Jun 2021 21:52:17 +0000 Subject: [PATCH 35/36] add ofproto 1.3 coverage, check key-error and attribute-error. --- ryu/controller/controller.py | 20 ++++---- ryu/controller/handler.py | 7 +-- ryu/controller/mac_to_port.py | 2 +- ryu/controller/ofp_api.py | 4 +- ryu/ofproto/ofproto_v1_3_parser.py | 80 +++++++++++++++++------------- setup.cfg | 3 +- 6 files changed, 65 insertions(+), 51 deletions(-) diff --git a/ryu/controller/controller.py b/ryu/controller/controller.py index 698e375e..1e86ed56 100644 --- a/ryu/controller/controller.py +++ b/ryu/controller/controller.py @@ -317,7 +317,8 @@ class Datapath(ofproto_protocol.ProtocolDesc): self.state = state ev = ofp_event.EventOFPStateChange(self) ev.state = state - self.ofp_brick.send_event_to_observers(ev, state) + if self.ofp_brick is not None: + self.ofp_brick.send_event_to_observers(ev, state) # Low level socket handling layer @_deactivate @@ -362,16 +363,17 @@ class Datapath(ofproto_protocol.ProtocolDesc): # LOG.debug('queue msg %s cls %s', msg, msg.__class__) if msg: ev = ofp_event.ofp_msg_to_ev(msg) - self.ofp_brick.send_event_to_observers(ev, self.state) + if self.ofp_brick is not None: + self.ofp_brick.send_event_to_observers(ev, self.state) - def dispatchers(x): - return x.callers[ev.__class__].dispatchers + def dispatchers(x): + return x.callers[ev.__class__].dispatchers - handlers = [handler for handler in - self.ofp_brick.get_handlers(ev) if - self.state in dispatchers(handler)] - for handler in handlers: - handler(ev) + handlers = [handler for handler in + self.ofp_brick.get_handlers(ev) if + self.state in dispatchers(handler)] + for handler in handlers: + handler(ev) buf = buf[msg_len:] buf_len = len(buf) diff --git a/ryu/controller/handler.py b/ryu/controller/handler.py index cda27bcc..c4f13283 100644 --- a/ryu/controller/handler.py +++ b/ryu/controller/handler.py @@ -149,6 +149,7 @@ def register_service(service): there are applications consuming OFP events. """ frame = inspect.currentframe() - m_name = frame.f_back.f_globals['__name__'] - m = sys.modules[m_name] - m._SERVICE_NAME = service + if frame is not None: + m_name = frame.f_back.f_globals['__name__'] + m = sys.modules[m_name] + m._SERVICE_NAME = service diff --git a/ryu/controller/mac_to_port.py b/ryu/controller/mac_to_port.py index 98472a2f..12b08bf3 100644 --- a/ryu/controller/mac_to_port.py +++ b/ryu/controller/mac_to_port.py @@ -50,7 +50,7 @@ class MacToPortTable(object): return self.mac_to_port[dpid].get(mac) def mac_list(self, dpid, port): - return [mac for (mac, port_) in self.mac_to_port.get(dpid).items() + return [mac for (mac, port_) in self.mac_to_port.get(dpid, {}).items() if port_ == port] def mac_del(self, dpid, mac): diff --git a/ryu/controller/ofp_api.py b/ryu/controller/ofp_api.py index 7a8f5f49..4b9ee737 100644 --- a/ryu/controller/ofp_api.py +++ b/ryu/controller/ofp_api.py @@ -47,7 +47,7 @@ def register_switch_address(addr, interval=None): def _retry_loop(): # Delays registration if ofp_handler is not started yet while True: - if ofp_handler.controller is not None: + if ofp_handler is not None and ofp_handler.controller is not None: for a, i in _TMP_ADDRESSES.items(): ofp_handler.controller.spawn_client_loop(a, i) hub.sleep(1) @@ -69,6 +69,6 @@ def unregister_switch_address(addr): """ ofp_handler = app_manager.lookup_service_brick(ofp_event.NAME) # Do nothing if ofp_handler is not started yet - if ofp_handler.controller is None: + if ofp_handler is None or ofp_handler.controller is None: return ofp_handler.controller.stop_client_loop(addr) diff --git a/ryu/ofproto/ofproto_v1_3_parser.py b/ryu/ofproto/ofproto_v1_3_parser.py index 0324c82b..34c49a3c 100644 --- a/ryu/ofproto/ofproto_v1_3_parser.py +++ b/ryu/ofproto/ofproto_v1_3_parser.py @@ -1754,7 +1754,7 @@ class OFPMatchField(StringifyMixin): (value, mask) = struct.unpack_from(pack_str, buf, offset + 4) else: (value,) = struct.unpack_from(cls.pack_str, buf, offset + 4) - return cls(header, value, mask) + return cls(header, value, mask) # pytype: disable=wrong-arg-count def serialize(self, buf, offset): if ofproto.oxm_tlv_header_extract_hasmask(self.header): @@ -2773,8 +2773,9 @@ class OFPFlowMod(MsgBase): try: while offset < msg_len: i = OFPInstruction.parser(buf, offset) - instructions.append(i) - offset += i.len + if i is not None: + instructions.append(i) + offset += i.len except exception.OFPTruncatedMessage as e: instructions.append(e.ofpmsg) msg.instructions = instructions @@ -2805,7 +2806,9 @@ class OFPInstruction(StringifyMixin): def parser(cls, buf, offset): (type_, len_) = struct.unpack_from('!HH', buf, offset) cls_ = cls._INSTRUCTION_TYPES.get(type_) - return cls_.parser(buf, offset) + if cls_ is not None: + return cls_.parser(buf, offset) + return None @OFPInstruction.register_instruction_type([ofproto.OFPIT_GOTO_TABLE]) @@ -3551,7 +3554,7 @@ class OFPActionExperimenter(OFPAction): data = buf[(offset + ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE ): offset + len_] if experimenter == ofproto_common.NX_EXPERIMENTER_ID: - obj = NXAction.parse(data) # noqa + obj = NXAction.parse(data) # pytype: disable=name-error # noqa else: obj = OFPActionExperimenterUnknown(experimenter, data) obj.len = len_ @@ -3932,22 +3935,23 @@ class OFPMultipartReply(MsgBase): ofproto.OFP_MULTIPART_REPLY_PACK_STR, six.binary_type(buf), ofproto.OFP_HEADER_SIZE) stats_type_cls = cls._STATS_MSG_TYPES.get(type_) - msg = super(OFPMultipartReply, stats_type_cls).parser( + msg = super(OFPMultipartReply, stats_type_cls).parser( # pytype: disable=attribute-error datapath, version, msg_type, msg_len, xid, buf) msg.type = type_ msg.flags = flags - offset = ofproto.OFP_MULTIPART_REPLY_SIZE - body = [] - while offset < msg_len: - b = stats_type_cls.cls_stats_body_cls.parser(msg.buf, offset) - body.append(b) - offset += b.length if hasattr(b, 'length') else b.len + if stats_type_cls is not None: + offset = ofproto.OFP_MULTIPART_REPLY_SIZE + body = [] + while offset < msg_len: + b = stats_type_cls.cls_stats_body_cls.parser(msg.buf, offset) + body.append(b) + offset += b.length if hasattr(b, 'length') else b.len - if stats_type_cls.cls_body_single_struct: - msg.body = body[0] - else: - msg.body = body + if stats_type_cls.cls_body_single_struct: + msg.body = body[0] + else: + msg.body = body return msg @@ -4577,12 +4581,13 @@ class OFPGroupStats(StringifyMixin): group_stats = cls(*group) group_stats.bucket_stats = [] - total_len = group_stats.length + offset - offset += ofproto.OFP_GROUP_STATS_SIZE - while total_len > offset: - b = OFPBucketCounter.parser(buf, offset) - group_stats.bucket_stats.append(b) - offset += ofproto.OFP_BUCKET_COUNTER_SIZE + if group_stats.length is not None: + total_len = group_stats.length + offset + offset += ofproto.OFP_GROUP_STATS_SIZE + while total_len > offset: + b = OFPBucketCounter.parser(buf, offset) + group_stats.bucket_stats.append(b) + offset += ofproto.OFP_BUCKET_COUNTER_SIZE return group_stats @@ -5770,7 +5775,7 @@ class ONFFlowMonitorRequest(StringifyMixin): match_len = match.length match_hdr_len = ofproto.OFP_MATCH_SIZE - 4 # exclude pad[4] # strip ofp_match header and trailing padding - bin_match = bytes(bin_match)[match_hdr_len:match_len] + bin_match = bytearray(bin_match)[match_hdr_len:match_len] self.match_len = len(bin_match) buf = bytearray() @@ -5936,14 +5941,16 @@ class OFPQueueProp(OFPQueuePropHeader): ofproto.OFP_QUEUE_PROP_HEADER_PACK_STR, buf, offset) cls_ = cls._QUEUE_PROP_PROPERTIES.get(property_) - p = cls_.parser(buf, offset + ofproto.OFP_QUEUE_PROP_HEADER_SIZE) - p.property = property_ - p.len = len_ - if property_ == ofproto.OFPQT_EXPERIMENTER: - rest = buf[offset + ofproto.OFP_QUEUE_PROP_EXPERIMENTER_SIZE: - offset + len_] - p.parse_experimenter_data(rest) - return p + if cls_ is not None: + p = cls_.parser(buf, offset + ofproto.OFP_QUEUE_PROP_HEADER_SIZE) + p.property = property_ + p.len = len_ + if property_ == ofproto.OFPQT_EXPERIMENTER: + rest = buf[offset + ofproto.OFP_QUEUE_PROP_EXPERIMENTER_SIZE: + offset + len_] + p.parse_experimenter_data(rest) + return p + return None @OFPQueueProp.register_property(ofproto.OFPQT_MIN_RATE, @@ -6017,9 +6024,10 @@ class OFPPacketQueue(StringifyMixin): properties = [] while length < len_: queue_prop = OFPQueueProp.parser(buf, offset) - properties.append(queue_prop) - offset += queue_prop.len - length += queue_prop.len + if queue_prop is not None: + properties.append(queue_prop) + offset += queue_prop.len + length += queue_prop.len o = cls(queue_id, port, properties) o.len = len_ return o @@ -6342,6 +6350,10 @@ class OFPSetAsync(MsgBase): self.flow_removed_mask[0], self.flow_removed_mask[1]) +class OFPBundleProp(OFPPropBase): + _TYPES = {} + + @_register_exp_type(ofproto_common.ONF_EXPERIMENTER_ID, ofproto.ONF_ET_BUNDLE_CONTROL) class ONFBundleCtrlMsg(OFPExperimenter): diff --git a/setup.cfg b/setup.cfg index 96208014..e1ff80cf 100644 --- a/setup.cfg +++ b/setup.cfg @@ -59,10 +59,9 @@ console_scripts = [pytype] inputs = ryu/controller/ + ryu/ofproto/ofproto_v1_3* disable = - attribute-error import-error - key-error module-attr keep-going = 1 From 824ee131136236f00962a5473a8f7ec6e15603b4 Mon Sep 17 00:00:00 2001 From: Josh Bailey Date: Mon, 26 Jul 2021 10:55:04 +1200 Subject: [PATCH 36/36] Eventlet 0.31.1 --- tools/pip-requires | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/pip-requires b/tools/pip-requires index 02f867ab..714cb3a6 100644 --- a/tools/pip-requires +++ b/tools/pip-requires @@ -2,7 +2,7 @@ # NOTE: OpenStack avoids some versions of eventlet, because of the # following issue. # https://github.com/eventlet/eventlet/issues/401 -eventlet==0.31.0 +eventlet==0.31.1 msgpack>=0.4.0 # RPC library, BGP speaker(net_cntl) netaddr oslo.config>=2.5.0