Merge branch 'master' into master

This commit is contained in:
Josh Bailey 2021-02-01 10:04:47 +13:00 committed by GitHub
commit 688fc4bf06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 506 additions and 263 deletions

25
.github/workflows/tests-unit.yml vendored Normal file
View File

@ -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, 3.9]
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_github_actions.sh
- name: Test with tox
run: NOSE_VERBOSE=0 tox

11
.readthedocs.yml Normal file
View File

@ -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

15
.renovaterc.json Normal file
View File

@ -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"
]
}

9
.stickler.yml Normal file
View File

@ -0,0 +1,9 @@
---
linters:
flake8:
python: 3
max-line-length: 120
pep8:
python: 3
max-line-length: 120
py3k:

View File

@ -1,43 +0,0 @@
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: 2.7
env: TOX_ENV=pycodestyle
- python: 2.7
env: TOX_ENV=py27
- python: 3.4
env: TOX_ENV=py34
- python: 3.5
env: TOX_ENV=py35
- python: 3.7-dev
env: TOX_ENV=py37
# 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

View File

@ -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 <https://github.com/faucetsdn/ryu>`_ 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,9 +30,9 @@ features (it's not a must though).
Python version and libraries
============================
* Python 2.7, 3.4, 3.5:
* Python 3.5, 3.6, 3.7, 3.8, 3.9:
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:

View File

@ -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,
@ -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
@ -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)::
@ -59,7 +59,7 @@ On Ubuntu(16.04 LTS or later)::
Support
=======
Ryu Official site is `<http://osrg.github.io/ryu/>`_.
Ryu Official site is `<https://ryu-sdn.org/>`_.
If you have any
questions, suggestions, and patches, the mailing list is available at

10
debian/control vendored
View File

@ -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.4.0),
python-netaddr,
python-oslo.config (>= 1:1.2.0),
python-paramiko,
@ -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
@ -28,7 +28,7 @@ Section: python
Depends:
python-eventlet,
python-lxml,
python-msgpack (>= 0.3.0),
python-msgpack (>= 0.4.0),
python-netaddr,
python-oslo.config (>= 1:1.2.0),
python-paramiko,

2
debian/copyright vendored
View File

@ -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 <ryu-devel@lists.sourceforge.net>

View File

@ -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

View File

@ -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.

View File

@ -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,24 +103,24 @@ 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
<https://github.com/osrg/ryu/blob/master/ryu/app/simple_switch.py>`_. You
<https://github.com/faucetsdn/ryu/blob/master/ryu/app/simple_switch.py>`_. You
can learn from the existing Ryu applications at `ryu/app
<https://github.com/osrg/ryu/blob/master/ryu/app/>`_ directory and
<https://github.com/faucetsdn/ryu/blob/master/ryu/app/>`_ directory and
`integrated tests
<https://github.com/osrg/ryu/blob/master/ryu/tests/integrated/>`_
<https://github.com/faucetsdn/ryu/blob/master/ryu/tests/integrated/>`_
directory.

View File

@ -14,5 +14,5 @@
# limitations under the License.
version_info = (4, 28)
version_info = (4, 34)
version = '.'.join(map(str, version_info))

View File

@ -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):

View File

@ -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)

View File

@ -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)

View File

@ -67,6 +67,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"'),
@ -165,6 +166,26 @@ 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.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),
@ -172,15 +193,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),

View File

@ -42,6 +42,7 @@ if HUB_TYPE == 'eventlet':
import ssl
import socket
import traceback
import sys
getcurrent = eventlet.getcurrent
patch = eventlet.monkey_patch
@ -126,11 +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)
handle(ssl.wrap_socket(sock, **ssl_args), 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'))
self.handle = wrap_and_handle
def wrap_and_handle_ctx(sock, addr):
handle(ctx.wrap_socket(sock, **ssl_args), addr)
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_ssl
else:
self.handle = handle

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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'

View File

@ -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
@ -2999,6 +2999,76 @@ 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 +3153,8 @@ def generate(ofp_name, ofpp_name):
'NXFlowSpecMatch',
'NXFlowSpecLoad',
'NXFlowSpecOutput',
'NXActionEncapNsh',
'NXActionEncapEther',
'NXActionDecNshTtl',
]
vars = locals()

View File

@ -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')
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

View File

@ -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)

View File

@ -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-----

View File

@ -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-----

View File

@ -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,53 @@ 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.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()
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))

View File

@ -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):

View File

@ -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)

View File

@ -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,

View File

@ -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

View File

@ -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 =
@ -13,12 +13,12 @@ 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
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Operating System :: Unix
keywords =
openflow

View File

@ -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

View File

@ -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):

View File

@ -1,12 +1,12 @@
# 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
msgpack>=0.3.0 # RPC library, BGP speaker(net_cntl)
eventlet==0.30.0
msgpack>=0.4.0 # RPC library, BGP speaker(net_cntl)
netaddr
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

15
tox.ini
View File

@ -1,5 +1,13 @@
[tox]
envlist = py27,py34,py35,py36,py37,pypy,pycodestyle,autopep8
envlist = py35,py36,py37,py38,py39,pypy,pycodestyle,autopep8
[gh-actions]
python =
3.5: py35
3.6: py36, pycodestyle, autopep8
3.7: py37
3.8: py38
3.9: py39
[testenv]
deps =
@ -20,11 +28,6 @@ commands =
commands =
python ryu/tests/integrated/run_test.py
[testenv:py27]
commands =
{[testenv]commands}
{[testenv:scenario]commands}
[testenv:py36]
commands =
{[testenv]commands}