Compare commits

..

No commits in common. "master" and "v3.29" have entirely different histories.

720 changed files with 18168 additions and 61213 deletions

View File

@ -1,25 +0,0 @@
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 -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
run: NOSE_VERBOSE=0 tox

View File

@ -10,6 +10,6 @@
# W0614: Unused import %s from wildcard import
# R0801: Similar lines in %s files
disable=C0111,W0511,W0142,E0602,C0103,E1101,R0903,W0614,R0801
msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg}
output-format=parseable
reports=yes
files-output=no

View File

@ -1,11 +0,0 @@
version: 2
build:
image: latest
python:
version: 3.6
install:
- method: pip
path: .
sphinx:
configuration: doc/source/conf.py
formats: all

View File

@ -1,15 +0,0 @@
{
"separateMajorMinor": false,
"schedule": [
"after 10pm every weekday",
"before 5am every weekday",
"every weekend"
],
"timezone": "Pacific/Auckland",
"extends": [
"config:base",
":prHourlyLimit1",
":preserveSemverRanges",
"docker:enableMajor"
]
}

View File

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

17
.travis.yml Normal file
View File

@ -0,0 +1,17 @@
language: python
python:
- "2.7"
env:
- TOX_ENV=py26
- TOX_ENV=py27
- TOX_ENV=py34
- TOX_ENV=pep8
install:
- "pip install tox"
script:
- NOSE_VERBOSE=0 tox -e $TOX_ENV
sudo: false

View File

@ -5,59 +5,46 @@ How to Get Your Change Into Ryu
Submitting a change
===================
To send patches to ryu, please make a
`pull request <https://github.com/faucetsdn/ryu>`_ on GitHub.
Send patches to ryu-devel@lists.sourceforge.net. Please don't use 'pull
request' on github. We expect you to send a patch in Linux kernel
development style. If you are not familiar with it, please read the
following document:
Please check your changes with autopep8, pycodestyle(pep8) and running
unit tests to make sure that they don't break the existing features.
The following command does all for you.
https://www.kernel.org/doc/Documentation/SubmittingPatches
.. code-block:: bash
Please check your changes with pep8 and run unittests to make sure
that they don't break the existing features. The following command
does both for you:
# Install dependencies of tests
$ pip install -r tools/test-requires
fujita@rose:~/git/ryu$ ./run_tests.sh
# Execute autopep8
# Also, it is convenient to add settings of your editor or IDE for
# applying autopep8 automatically.
$ autopep8 --recursive --in-place ryu/
# Execute unit tests and pycodestyle(pep8)
$ ./run_tests.sh
Of course, you are encouraged to add unit tests when you add new
Of course, you are encouraged to add unittests when you add new
features (it's not a must though).
Python version and libraries
============================
* Python 3.5, 3.6, 3.7, 3.8, 3.9:
* Python 2.6+
As RHEL 6 adopted python 2.6, features only for 2.7+ should be avoided.
Ryu supports multiple Python versions. CI tests on GitHub Actions is running
on these versions.
* standard library + widely used library:
Basically widely used == OpenStack adopted.
As usual there are exceptions. Or python binding library for other
* standard library + widely used library
Basically widely used == OpenStack adopted
As usual there are exceptions. gevents. Or python binding library for other
component.
Coding style guide
==================
* pep8:
* pep8
As python is used, PEP8 is would be hopefully mandatory for
https://www.python.org/dev/peps/pep-0008/
* pylint:
http://www.python.org/dev/peps/pep-0008/
* pylint
Although pylint is useful for finding bugs, but pylint score not very
important for now because we're still at early development stage.
https://www.pylint.org/
* Google python style guide is very helpful:
http://google.github.io/styleguide/pyguide.html
* Google python style guide is very helpful
http://google-styleguide.googlecode.com/svn/trunk/pyguide.html
* Guidelines derived from Guido's Recommendations:
Guidelines derived from Guido's Recommendations
============================= ================= ========
Type Public Internal
@ -75,11 +62,10 @@ Coding style guide
Local Variables lower_with_under
============================= ================= ========
* OpenStack Nova style guide:
* OpenStack Nova style guide
https://github.com/openstack/nova/blob/master/HACKING.rst
* JSON files:
* JSON files
Ryu source tree has JSON files under ryu/tests/unit/ofproto/json.
They are used by unit tests. To make patches easier to read,
they are normalized using tools/normalize_json.py. Please re-run

View File

@ -1,13 +1,8 @@
**PLEASE READ: RYU NOT CURRENTLY MAINTAINED**
* The Ryu project needs new maintainers - please file an issue if you are able to assist.
* see OpenStack's os-ken (`<https://github.com/openstack/os-ken>`_) for a maintained Ryu alternative.
What's Ryu
==========
Ryu is a component-based software defined networking framework.
Ryu provides software components with well defined API's that make it
Ryu provides software components with well defined API 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,
@ -25,11 +20,14 @@ Installing Ryu is quite easy::
If you prefer to install Ryu from the source code::
% git clone https://github.com/faucetsdn/ryu.git
% cd ryu; pip install .
% git clone git://github.com/osrg/ryu.git
% cd ryu; python ./setup.py install
If you want to use Ryu with `OpenStack <http://openstack.org/>`_,
please refer `networking-ofagent project <https://github.com/stackforge/networking-ofagent>`_.
If you want to write your Ryu application, have a look at
`Writing ryu application <http://ryu.readthedocs.io/en/latest/writing_ryu_app.html>`_ document.
`Writing ryu application <http://ryu.readthedocs.org/en/latest/writing_ryu_app.html>`_ document.
After writing your application, just type::
% ryu-manager yourapp.py
@ -38,33 +36,21 @@ After writing your application, just type::
Optional Requirements
=====================
Some functions of ryu require extra packages:
Some functionalities of ryu requires extra packages:
- OF-Config requires lxml and ncclient
- OF-Config requires lxml
- NETCONF requires paramiko
- BGP speaker (SSH console) requires paramiko
- Zebra protocol service (database) requires SQLAlchemy
- BGP speaker (ssh console) requires paramiko
If you want to use these functions, please install the requirements::
If you want to use the functionalities, please install requirements::
% pip install -r tools/optional-requires
Please refer to tools/optional-requires for details.
Prerequisites
=============
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)::
% apt install gcc python-dev libffi-dev libssl-dev libxml2-dev libxslt1-dev zlib1g-dev
% pip install lxml
% pip install paramiko
Support
=======
Ryu Official site is `<https://ryu-sdn.org/>`_.
Ryu Official site is `<http://osrg.github.io/ryu/>`_.
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.4.0),
python-msgpack (>= 0.3.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: https://ryu-sdn.org
Vcs-Git: git://github.com/faucetsdn/ryu.git
Vcs-Browser: https://github.com/faucetsdn/ryu
Homepage: http://osrg.github.io/ryu/
Vcs-Git: git://github.com/osrg/ryu.git
Vcs-Browser: http://github.com/osrg/ryu
XS-Python-Version: >= 2.6
Package: python-ryu
@ -28,7 +28,7 @@ Section: python
Depends:
python-eventlet,
python-lxml,
python-msgpack (>= 0.4.0),
python-msgpack (>= 0.3.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/faucetsdn/ryu
Source: http://github.com/osrg/ryu
Files: *
Copyright: 2014 Ryu Project Team <ryu-devel@lists.sourceforge.net>

View File

@ -11,5 +11,3 @@ Others provide some functionalities to other Ryu applications.
app/ofctl.rst
app/ofctl_rest.rst
app/rest_vtep.rst
app/bgp_application.rst

View File

@ -1,6 +0,0 @@
**************************************
ryu.services.protocols.bgp.application
**************************************
.. automodule:: ryu.services.protocols.bgp.application
:members:

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
*****************
ryu.app.rest_vtep
*****************
.. automodule:: ryu.app.rest_vtep
REST API
========
.. autoclass:: ryu.app.rest_vtep.RestVtepController
:members:
:member-order: bysource

View File

@ -132,7 +132,6 @@ html_static_path = ['_static']
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# (Deprecated since version 1.6)
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}

View File

@ -10,5 +10,4 @@ Writing Your Ryu Application
ryu_app_api.rst
library.rst
ofproto_ref.rst
nicira_ext_ref.rst
api_ref.rst

View File

@ -1,2 +0,0 @@
[parsers]
smart_quotes: false

View File

@ -16,6 +16,7 @@ Contents:
developing.rst
configuration.rst
tests.rst
using_with_openstack.rst
snort_integrate.rst
app.rst

View File

@ -9,10 +9,7 @@ Ryu provides some useful library for your network applications.
library_packet.rst
library_packet_ref.rst
library_pcap.rst
library_of_config.rst
library_bgp_speaker.rst
library_bgp_speaker_ref.rst
library_mrt.rst
library_ovsdb_manager.rst
library_ovsdb.rst

View File

@ -6,8 +6,8 @@ Introduction
============
Ryu BGP speaker library helps you to enable your code to speak BGP
protocol. The library supports IPv4, IPv4 MPLS-labeled VPN, IPv6
MPLS-labeled VPN and L2VPN EVPN address families.
protocol. The library supports ipv4, ipv4 vpn, and ipv6 vpn address
families.
Example
=======

View File

@ -1,28 +0,0 @@
****************
MRT file library
****************
Introduction
============
Ryu MRT file library helps you to read/write MRT
(Multi-Threaded Routing Toolkit) Routing Information Export Format
[`RFC6396`_].
.. _RFC6396: https://tools.ietf.org/html/rfc6396
Reading MRT file
================
For loading the routing information contained in MRT files, you can use
mrtlib.Reader.
.. autoclass:: ryu.lib.mrtlib.Reader
Writing MRT file
================
For dumping the routing information which your RyuApp generated, you can use
mrtlib.Writer.
.. autoclass:: ryu.lib.mrtlib.Writer

View File

@ -1,76 +0,0 @@
*************
OVSDB library
*************
Path: ``ryu.lib.ovs``
Similar to the :doc:`library_ovsdb_manager`, this library enables your
application to speak the OVSDB protocol (RFC7047_), but differ from the
:doc:`library_ovsdb_manager`, this library will initiate connections from
controller side as ovs-vsctl_ command does.
Please make sure that your devices are listening on either the Unix domain
socket or TCP/SSL port before calling the APIs of this library.
.. code-block:: bash
# Show current configuration
$ ovs-vsctl get-manager
# Set TCP listen address
$ ovs-vsctl set-manager "ptcp:6640"
See manpage of ovs-vsctl_ command for more details.
.. _RFC7047: https://tools.ietf.org/html/rfc7047
.. _ovs-vsctl: http://openvswitch.org/support/dist-docs/ovs-vsctl.8.txt
Basic Usage
===========
1. Instantiate :py:mod:`ryu.lib.ovs.vsctl.VSCtl`.
2. Construct commands with :py:mod:`ryu.lib.ovs.vsctl.VSCtlCommand`.
The syntax is almost the same as ovs-vsctl_ command.
3. Execute commands via :py:mod:`ryu.lib.ovs.vsctl.VSCtl.run_command`.
Example
-------
.. code-block:: python
from ryu.lib.ovs import vsctl
OVSDB_ADDR = 'tcp:127.0.0.1:6640'
ovs_vsctl = vsctl.VSCtl(OVSDB_ADDR)
# Equivalent to
# $ ovs-vsctl show
command = vsctl.VSCtlCommand('show')
ovs_vsctl.run_command([command])
print(command)
# >>> VSCtlCommand(args=[],command='show',options=[],result='830d781f-c3c8-4b4f-837e-106e1b33d058\n ovs_version: "2.8.90"\n')
# Equivalent to
# $ ovs-vsctl list Port s1-eth1
command = vsctl.VSCtlCommand('list', ('Port', 's1-eth1'))
ovs_vsctl.run_command([command])
print(command)
# >>> VSCtlCommand(args=('Port', 's1-eth1'),command='list',options=[],result=[<ovs.db.idl.Row object at 0x7f525fb682e8>])
print(command.result[0].name)
# >>> s1-eth1
API Reference
=============
ryu.lib.ovs.vsctl
-----------------
.. automodule:: ryu.lib.ovs.vsctl
:members:
ryu.lib.ovs.bridge
------------------
.. automodule:: ryu.lib.ovs.bridge
:members:

View File

@ -2,8 +2,6 @@
OVSDB Manager library
*********************
Path: ``ryu.services.protocols.ovsdb``
Introduction
============
@ -11,47 +9,17 @@ Ryu OVSDB Manager library allows your code to interact with devices
speaking the OVSDB protocol. This enables your code to perform remote
management of the devices and react to topology changes on them.
Please note this library will spawn a server listening on the port 6640 (the
IANA registered for OVSDB protocol), but does not initiate connections from
controller side.
Then, to make your devices connect to Ryu, you need to tell the controller IP
address and port to your devices.
.. code-block:: bash
# Show current configuration
$ ovs-vsctl get-manager
# Set manager (controller) address
$ ovs-vsctl set-manager "tcp:127.0.0.1:6640"
# If you want to specify IPv6 address, wrap ip with brackets
$ ovs-vsctl set-manager "tcp:[::1]:6640"
Also this library identifies the devices by "system-id" which should be unique,
persistent identifier among all devices connecting to a single controller.
Please make sure "system-id" is configured before connecting.
.. code-block:: bash
# Show current configuration
$ ovs-vsctl get Open_vSwitch . external_ids:system-id
# Set system-id manually
$ ovs-vsctl set Open_vSwitch . external_ids:system-id=<SYSTEM-ID>
Example
=======
The following logs all new OVSDB connections in "handle_new_ovsdb_connection"
and also provides the API "create_port" for creating a port on a bridge.
The following logs all new OVSDB connections and allows creating a port
on a bridge.
.. code-block:: python
import uuid
from ryu.base import app_manager
from ryu.controller.handler import set_ev_cls
from ryu.services.protocols.ovsdb import api as ovsdb
from ryu.services.protocols.ovsdb import event as ovsdb_event
@ -60,22 +28,16 @@ and also provides the API "create_port" for creating a port on a bridge.
@set_ev_cls(ovsdb_event.EventNewOVSDBConnection)
def handle_new_ovsdb_connection(self, ev):
system_id = ev.system_id
address = ev.client.address
self.logger.info(
'New OVSDB connection from system-id=%s, address=%s',
system_id, address)
self.logger.info('New OVSDB connection from system id %s',
systemd_id)
# Example: If device has bridge "s1", add port "s1-eth99"
if ovsdb.bridge_exists(self, system_id, "s1"):
self.create_port(system_id, "s1", "s1-eth99")
def create_port(self, system_id, bridge_name, name):
def create_port(self, systemd_id, bridge_name, name):
new_iface_uuid = uuid.uuid4()
new_port_uuid = uuid.uuid4()
bridge = ovsdb.row_by_name(self, system_id, bridge_name)
def _create_port(tables, insert):
bridge = ovsdb.row_by_name(self, system_id, bridge_name)
iface = insert(tables['Interface'], new_iface_uuid)
iface.name = name
iface.type = 'internal'
@ -84,9 +46,9 @@ and also provides the API "create_port" for creating a port on a bridge.
port.name = name
port.interfaces = [iface]
bridge.ports = bridge.ports + [port]
brdige.ports = bridfe.ports + [port]
return new_port_uuid, new_iface_uuid
return (new_port_uuid, new_iface_uuid)
req = ovsdb_event.EventModifyRequest(system_id, _create_port)
rep = self.send_request(req)
@ -96,4 +58,4 @@ and also provides the API "create_port" for creating a port on a bridge.
name, bridge, rep.status)
return None
return rep.insert_uuids[new_port_uuid]
return reply.insert_uuid[new_port_uuid]

View File

@ -14,15 +14,119 @@ Stream Parser class
.. automodule:: ryu.lib.packet.stream_parser
:members:
List of the sub-classes:
- :py:mod:`ryu.lib.packet.bgp.StreamParser`
.. autoclass:: ryu.lib.packet.bgp.StreamParser
:members:
Protocol Header classes
=======================
.. toctree::
:glob:
.. automodule:: ryu.lib.packet.packet_base
:members:
library_packet_ref/packet_base
library_packet_ref/*
.. automodule:: ryu.lib.packet.ethernet
:members:
.. automodule:: ryu.lib.packet.vlan
:members:
.. automodule:: ryu.lib.packet.pbb
:members:
.. automodule:: ryu.lib.packet.mpls
:members:
.. automodule:: ryu.lib.packet.arp
:members:
.. automodule:: ryu.lib.packet.ipv4
:members:
.. automodule:: ryu.lib.packet.icmp
:members:
.. automodule:: ryu.lib.packet.ipv6
:members:
.. automodule:: ryu.lib.packet.icmpv6
:members:
.. automodule:: ryu.lib.packet.cfm
:members:
.. automodule:: ryu.lib.packet.tcp
:members:
.. automodule:: ryu.lib.packet.udp
:members:
.. autoclass:: ryu.lib.packet.dhcp.dhcp
:members:
.. autoclass:: ryu.lib.packet.dhcp.options
:members:
.. autoclass:: ryu.lib.packet.dhcp.option
:members:
.. autoclass:: ryu.lib.packet.vrrp.vrrp
:members:
.. autoclass:: ryu.lib.packet.vrrp.vrrpv2
:members:
.. autoclass:: ryu.lib.packet.vrrp.vrrpv3
:members:
.. autoclass:: ryu.lib.packet.slow.slow
:members:
.. autoclass:: ryu.lib.packet.slow.lacp
:members:
.. autoclass:: ryu.lib.packet.llc.llc
:members:
.. autoclass:: ryu.lib.packet.llc.ControlFormatI
:members:
.. autoclass:: ryu.lib.packet.llc.ControlFormatS
:members:
.. autoclass:: ryu.lib.packet.llc.ControlFormatU
:members:
.. autoclass:: ryu.lib.packet.bpdu.bpdu
:members:
.. autoclass:: ryu.lib.packet.bpdu.ConfigurationBPDUs
:members:
.. autoclass:: ryu.lib.packet.bpdu.TopologyChangeNotificationBPDUs
:members:
.. autoclass:: ryu.lib.packet.bpdu.RstBPDUs
:members:
.. autoclass:: ryu.lib.packet.igmp.igmp
:members:
.. autoclass:: ryu.lib.packet.igmp.igmpv3_query
:members:
.. autoclass:: ryu.lib.packet.igmp.igmpv3_report
:members:
.. autoclass:: ryu.lib.packet.igmp.igmpv3_report_group
:members:
.. autoclass:: ryu.lib.packet.bgp.BGPMessage
:members:
.. autoclass:: ryu.lib.packet.bgp.BGPOpen
:members:
.. autoclass:: ryu.lib.packet.bgp.BGPUpdate
:members:
.. autoclass:: ryu.lib.packet.bgp.BGPKeepAlive
:members:
.. autoclass:: ryu.lib.packet.bgp.BGPNotification
:members:
.. automodule:: ryu.lib.packet.sctp
:members:
.. autoclass:: ryu.lib.packet.bfd.bfd
:members:
.. autoclass:: ryu.lib.packet.bfd.SimplePassword
:members:
.. autoclass:: ryu.lib.packet.bfd.KeyedMD5
:members:
.. autoclass:: ryu.lib.packet.bfd.MeticulousKeyedMD5
:members:
.. autoclass:: ryu.lib.packet.bfd.KeyedSHA1
:members:
.. autoclass:: ryu.lib.packet.bfd.MeticulousKeyedSHA1
:members:

View File

@ -1,6 +0,0 @@
***
ARP
***
.. automodule:: ryu.lib.packet.arp
:members:

View File

@ -1,6 +0,0 @@
*****************
Packet Base Class
*****************
.. automodule:: ryu.lib.packet.packet_base
:members:

View File

@ -1,6 +0,0 @@
***
BFD
***
.. automodule:: ryu.lib.packet.bfd
:members:

View File

@ -1,6 +0,0 @@
***
BGP
***
.. automodule:: ryu.lib.packet.bgp
:members:

View File

@ -1,6 +0,0 @@
***
BMP
***
.. automodule:: ryu.lib.packet.bmp
:members:

View File

@ -1,6 +0,0 @@
****
BPDU
****
.. automodule:: ryu.lib.packet.bpdu
:members:

View File

@ -1,6 +0,0 @@
***
CFM
***
.. automodule:: ryu.lib.packet.cfm
:members:

View File

@ -1,6 +0,0 @@
****
DHCP
****
.. automodule:: ryu.lib.packet.dhcp
:members:

View File

@ -1,6 +0,0 @@
*****
DHCP6
*****
.. automodule:: ryu.lib.packet.dhcp6
:members:

View File

@ -1,6 +0,0 @@
********
Ethernet
********
.. automodule:: ryu.lib.packet.ethernet
:members:

View File

@ -1,6 +0,0 @@
******
Geneve
******
.. automodule:: ryu.lib.packet.geneve
:members:

View File

@ -1,6 +0,0 @@
***
GRE
***
.. automodule:: ryu.lib.packet.gre
:members:

View File

@ -1,6 +0,0 @@
****
ICMP
****
.. automodule:: ryu.lib.packet.icmp
:members:

View File

@ -1,6 +0,0 @@
******
ICMPv6
******
.. automodule:: ryu.lib.packet.icmpv6
:members:

View File

@ -1,6 +0,0 @@
****
IGMP
****
.. automodule:: ryu.lib.packet.igmp
:members:

View File

@ -1,6 +0,0 @@
****
IPv4
****
.. automodule:: ryu.lib.packet.ipv4
:members:

View File

@ -1,6 +0,0 @@
****
IPv6
****
.. automodule:: ryu.lib.packet.ipv6
:members:

View File

@ -1,6 +0,0 @@
***
LLC
***
.. automodule:: ryu.lib.packet.llc
:members:

View File

@ -1,6 +0,0 @@
****
LLDP
****
.. automodule:: ryu.lib.packet.lldp
:members:

View File

@ -1,6 +0,0 @@
****
MPLS
****
.. automodule:: ryu.lib.packet.mpls
:members:

View File

@ -1,6 +0,0 @@
********
OpenFlow
********
.. automodule:: ryu.lib.packet.openflow
:members:

View File

@ -1,6 +0,0 @@
****
OSPF
****
.. automodule:: ryu.lib.packet.ospf
:members:

View File

@ -1,6 +0,0 @@
***
PBB
***
.. automodule:: ryu.lib.packet.pbb
:members:

View File

@ -1,6 +0,0 @@
****
SCTP
****
.. automodule:: ryu.lib.packet.sctp
:members:

View File

@ -1,6 +0,0 @@
****
Slow
****
.. automodule:: ryu.lib.packet.slow
:members:

View File

@ -1,6 +0,0 @@
***
TCP
***
.. automodule:: ryu.lib.packet.tcp
:members:

View File

@ -1,6 +0,0 @@
***
UDP
***
.. automodule:: ryu.lib.packet.udp
:members:

View File

@ -1,6 +0,0 @@
****
VLAN
****
.. automodule:: ryu.lib.packet.vlan
:members:

View File

@ -1,6 +0,0 @@
****
VRRP
****
.. automodule:: ryu.lib.packet.vrrp
:members:

View File

@ -1,6 +0,0 @@
*****
VXLAN
*****
.. automodule:: ryu.lib.packet.vxlan
:members:

View File

@ -1,6 +0,0 @@
*****
Zebra
*****
.. automodule:: ryu.lib.packet.zebra
:members:

View File

@ -1,27 +0,0 @@
*****************
PCAP file library
*****************
Introduction
============
Ryu PCAP file library helps you to read/write PCAP file which file
format are described in `The Wireshark Wiki`_.
.. _The Wireshark Wiki: https://wiki.wireshark.org/Development/LibpcapFileFormat
Reading PCAP file
=================
For loading the packet data containing in PCAP files, you can use
pcaplib.Reader.
.. autoclass:: ryu.lib.pcaplib.Reader
Writing PCAP file
=================
For dumping the packet data which your RyuApp received, you can use
pcaplib.Writer.
.. autoclass:: ryu.lib.pcaplib.Writer

View File

@ -1,69 +0,0 @@
***************************
Nicira Extension Structures
***************************
.. _nx_actions_structures:
Nicira Extension Actions Structures
===================================
The followings shows the supported NXAction classes only in OpenFlow1.0
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. py:currentmodule:: ryu.ofproto.ofproto_v1_0_parser
.. autoclass:: NXActionSetQueue
.. autoclass:: NXActionDecTtl
.. autoclass:: NXActionPushMpls
.. autoclass:: NXActionPopMpls
.. autoclass:: NXActionSetMplsTtl
.. autoclass:: NXActionDecMplsTtl
.. autoclass:: NXActionSetMplsLabel
.. autoclass:: NXActionSetMplsTc
The followings shows the supported NXAction classes in OpenFlow1.0 or later
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. py:currentmodule:: ryu.ofproto.ofproto_v1_3_parser
.. autoclass:: NXActionPopQueue
.. autoclass:: NXActionRegLoad
.. autoclass:: NXActionRegLoad2
.. autoclass:: NXActionNote
.. autoclass:: NXActionSetTunnel
.. autoclass:: NXActionSetTunnel64
.. autoclass:: NXActionRegMove
.. autoclass:: NXActionResubmit
.. autoclass:: NXActionResubmitTable
.. autoclass:: NXActionOutputReg
.. autoclass:: NXActionOutputReg2
.. autoclass:: NXActionLearn
.. autoclass:: NXActionExit
.. autoclass:: NXActionController
.. autoclass:: NXActionController2
.. autoclass:: NXActionDecTtlCntIds
.. autoclass:: NXActionStackPush
.. autoclass:: NXActionStackPop
.. autoclass:: NXActionSample
.. autoclass:: NXActionSample2
.. autoclass:: NXActionFinTimeout
.. autoclass:: NXActionConjunction
.. autoclass:: NXActionMultipath
.. autoclass:: NXActionBundle
.. autoclass:: NXActionBundleLoad
.. autoclass:: NXActionCT
.. autoclass:: NXActionNAT
.. autoclass:: NXActionOutputTrunc
.. autoclass:: NXActionDecNshTtl
.. autoclass:: NXFlowSpecMatch
.. autoclass:: NXFlowSpecLoad
.. autoclass:: NXFlowSpecOutput
.. autofunction:: ryu.ofproto.nicira_ext.ofs_nbits
.. _nx_match_structures:
Nicira Extended Match Structures
================================
.. automodule:: ryu.ofproto.nicira_ext

View File

@ -11,7 +11,7 @@ Threads, events, and event queues
Ryu applications are single-threaded entities which implement
various functionalities in Ryu. Events are messages between them.
Ryu applications send asynchronous events to each other.
Ryu applications send asynchronous events each other.
Besides that, there are some Ryu-internal event sources which
are not Ryu applications. One of examples of such event sources
is OpenFlow controller.
@ -22,11 +22,11 @@ between Ryu applications.
Each Ryu application has a receive queue for events.
The queue is FIFO and preserves the order of events.
Each Ryu application has a thread for event processing.
The thread keeps draining the receive queue by dequeueing an event
The thread keep draining the receive queue by dequeueing an event
and calling the appropritate event handler for the event type.
Because the event handler is called in the context of
the event processing thread, it should be careful when blocking.
While an event handler is blocked, no further events for
the event processing thread, it should be careful for blocking.
I.e. while an event handler is blocked, no further events for
the Ryu application will be processed.
There are kinds of events which are used to implement synchronous
@ -82,10 +82,20 @@ For example, EventOFPPacketIn for packet-in message.
The OpenFlow controller part of Ryu automatically decodes OpenFlow messages
received from switches and send these events to Ryu applications which
expressed an interest using ryu.controller.handler.set_ev_cls.
OpenFlow event classes are subclasses of the following class.
OpenFlow event classes have at least the following attributes.
.. autoclass:: ryu.controller.ofp_event.EventOFPMsgBase
.. tabularcolumns:: |l|L|
============ =============================================================
Attribute Description
============ =============================================================
msg An object which describes the corresponding OpenFlow message.
msg.datapath A ryu.controller.controller.Datapath instance which describes
an OpenFlow switch from which we received this OpenFlow message.
============ =============================================================
The msg object has some more additional members whose values are extracted
from the original OpenFlow message.
See :ref:`ofproto_ref` for more info about OpenFlow messages.
ryu.base.app_manager.RyuApp
@ -93,87 +103,267 @@ ryu.base.app_manager.RyuApp
See :ref:`api_ref`.
ryu.controller.handler.set_ev_cls
=================================
ryu.controller.handler.set_ev_cls(ev_cls, dispatchers=None)
===========================================================
.. autofunction:: ryu.controller.handler.set_ev_cls
A decorator for Ryu application to declare an event handler.
Decorated method will become an event handler.
ev_cls is an event class whose instances this RyuApp wants to receive.
dispatchers argument specifies one of the following negotiation phases
(or a list of them) for which events should be generated for this handler.
Note that, in case an event changes the phase, the phase before the change
is used to check the interest.
.. tabularcolumns:: |l|L|
=========================================== ==================================
Negotiation phase Description
=========================================== ==================================
ryu.controller.handler.HANDSHAKE_DISPATCHER Sending and waiting for hello
message
ryu.controller.handler.CONFIG_DISPATCHER Version negotiated and sent
features-request message
ryu.controller.handler.MAIN_DISPATCHER Switch-features message received
and sent set-config message
ryu.controller.handler.DEAD_DISPATCHER Disconnect from the peer. Or
disconnecting due to some
unrecoverable errors.
=========================================== ==================================
ryu.controller.controller.Datapath
==================================
.. autoclass:: ryu.controller.controller.Datapath
A class to describe an OpenFlow switch connected to this controller.
An instance has the following attributes.
.. tabularcolumns:: |l|L|
====================================== =======================================
Attribute Description
====================================== =======================================
id 64-bit OpenFlow Datapath ID.
Only available for
ryu.controller.handler.MAIN_DISPATCHER
phase.
ofproto A module which exports OpenFlow
definitions, mainly constants appeared
in the specification, for the
negotiated OpenFlow version. For
example, ryu.ofproto.ofproto_v1_0 for
OpenFlow 1.0.
ofproto_parser A module which exports OpenFlow wire
message encoder and decoder for the
negotiated OpenFlow version. For
example, ryu.ofproto.ofproto_v1_0_parser
for OpenFlow 1.0.
ofproto_parser.OFPxxxx(datapath, ....) A callable to prepare an OpenFlow
message for the given switch. It can
be sent with Datapath.send_msg later.
xxxx is a name of the message. For
example OFPFlowMod for flow-mod
message. Arguemnts depend on the
message.
set_xid(self, msg) Generate an OpenFlow XID and put it
in msg.xid.
send_msg(self, msg) Queue an OpenFlow message to send to
the corresponding switch. If msg.xid
is None, set_xid is automatically
called on the message before queueing.
send_packet_out deprecated
send_flow_mod deprecated
send_flow_del deprecated
send_delete_all_flows deprecated
send_barrier Queue an OpenFlow barrier message to
send to the switch.
send_nxt_set_flow_format deprecated
is_reserved_port deprecated
====================================== =======================================
ryu.controller.event.EventBase
==============================
.. autoclass:: ryu.controller.event.EventBase
The base of all event classes.
A Ryu application can define its own event type by creating a subclass.
ryu.controller.event.EventRequestBase
=====================================
.. autoclass:: ryu.controller.event.EventRequestBase
The base class for synchronous request for RyuApp.send_request.
ryu.controller.event.EventReplyBase
===================================
.. autoclass:: ryu.controller.event.EventReplyBase
The base class for synchronous request reply for RyuApp.send_reply.
ryu.controller.ofp_event.EventOFPStateChange
============================================
.. autoclass:: ryu.controller.ofp_event.EventOFPStateChange
An event class for negotiation phase change notification.
An instance of this class is sent to observer after changing
the negotiation phase.
An instance has at least the following attributes.
ryu.controller.ofp_event.EventOFPPortStateChange
================================================
.. autoclass:: ryu.controller.ofp_event.EventOFPPortStateChange
========= ====================================================================
Attribute Description
========= ====================================================================
datapath ryu.controller.controller.Datapath instance of the switch
========= ====================================================================
ryu.controller.dpset.EventDP
============================
.. autoclass:: ryu.controller.dpset.EventDP
An event class to notify connect/disconnect of a switch.
For OpenFlow switches, one can get the same notification by observing
ryu.controller.ofp_event.EventOFPStateChange.
An instance has at least the following attributes.
========= ====================================================================
Attribute Description
========= ====================================================================
dp A ryu.controller.controller.Datapath instance of the switch
enter True when the switch connected to our controller. False for
disconnect.
========= ====================================================================
ryu.controller.dpset.EventPortAdd
=================================
.. autoclass:: ryu.controller.dpset.EventPortAdd
An event class for switch port status notification.
This event is generated when a new port is added to a switch.
For OpenFlow switches, one can get the same notification by observing
ryu.controller.ofp_event.EventOFPPortStatus.
An instance has at least the following attributes.
========= ====================================================================
Attribute Description
========= ====================================================================
dp A ryu.controller.controller.Datapath instance of the switch
port port number
========= ====================================================================
ryu.controller.dpset.EventPortDelete
====================================
.. autoclass:: ryu.controller.dpset.EventPortDelete
An event class for switch port status notification.
This event is generated when a port is removed from a switch.
For OpenFlow switches, one can get the same notification by observing
ryu.controller.ofp_event.EventOFPPortStatus.
An instance has at least the following attributes.
========= ====================================================================
Attribute Description
========= ====================================================================
dp A ryu.controller.controller.Datapath instance of the switch
port port number
========= ====================================================================
ryu.controller.dpset.EventPortModify
====================================
.. autoclass:: ryu.controller.dpset.EventPortModify
An event class for switch port status notification.
This event is generated when some attribute of a port is changed.
For OpenFlow switches, one can get the same notification by observing
ryu.controller.ofp_event.EventOFPPortStatus.
An instance has at least the following attributes.
========= ====================================================================
Attribute Description
========= ====================================================================
dp A ryu.controller.controller.Datapath instance of the switch
port port number
========= ====================================================================
ryu.controller.network.EventNetworkPort
=======================================
.. autoclass:: ryu.controller.network.EventNetworkPort
An event class for notification of port arrival and deperture.
This event is generated when a port is introduced to or removed from a network
by the REST API.
An instance has at least the following attributes.
========== ===================================================================
Attribute Description
========== ===================================================================
network_id Network ID
dpid OpenFlow Datapath ID of the switch to which the port belongs.
port_no OpenFlow port number of the port
add_del True for adding a port. False for removing a port.
========== ===================================================================
ryu.controller.network.EventNetworkDel
======================================
.. autoclass:: ryu.controller.network.EventNetworkDel
An event class for network deletion.
This event is generated when a network is deleted by the REST API.
An instance has at least the following attributes.
========== ===================================================================
Attribute Description
========== ===================================================================
network_id Network ID
========== ===================================================================
ryu.controller.network.EventMacAddress
======================================
.. autoclass:: ryu.controller.network.EventMacAddress
An event class for end-point MAC address registration.
This event is generated when a end-point MAC address is updated
by the REST API.
An instance has at least the following attributes.
=========== ==================================================================
Attribute Description
=========== ==================================================================
network_id Network ID
dpid OpenFlow Datapath ID of the switch to which the port belongs.
port_no OpenFlow port number of the port
mac_address The old MAC address of the port if add_del is False. Otherwise
the new MAC address.
add_del False if this event is a result of a port removal. Otherwise
True.
=========== ==================================================================
ryu.controller.tunnels.EventTunnelKeyAdd
========================================
.. autoclass:: ryu.controller.tunnels.EventTunnelKeyAdd
An event class for tunnel key registration.
This event is generated when a tunnel key is registered or updated
by the REST API.
An instance has at least the following attributes.
=========== ==================================================================
Attribute Description
=========== ==================================================================
network_id Network ID
tunnel_key Tunnel Key
=========== ==================================================================
ryu.controller.tunnels.EventTunnelKeyDel
========================================
.. autoclass:: ryu.controller.tunnels.EventTunnelKeyDel
An event class for tunnel key registration.
This event is generated when a tunnel key is removed by the REST API.
An instance has at least the following attributes.
=========== ==================================================================
Attribute Description
=========== ==================================================================
network_id Network ID
tunnel_key Tunnel Key
=========== ==================================================================
ryu.controller.tunnels.EventTunnelPort
======================================
.. autoclass:: ryu.controller.tunnels.EventTunnelPort
An event class for tunnel port registration.
This event is generated when a tunnel port is added or removed by the REST API.
An instance has at least the following attributes.
=========== ==================================================================
Attribute Description
=========== ==================================================================
dpid OpenFlow Datapath ID
port_no OpenFlow port number
remote_dpid OpenFlow port number of the tunnel peer
add_del True for adding a tunnel. False for removal.
=========== ==================================================================

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 https://ryu-sdn.org/
For getting/installing Ryu itself, please refer to http://osrg.github.io/ryu/
Install Erlang environment

View File

@ -4,17 +4,10 @@
Using Ryu Network Operating System with OpenStack as OpenFlow controller
************************************************************************
.. CAUTION::
The Ryu plugin and OFAgent described in the following is deprecated,
because Ryu is officially integrated into Open vSwitch agent with
"of_interface = native" mode.
Ryu cooperates with OpenStack using Quantum Ryu plugin. The plugin is
available in the official Quantum releases.
For more information, please visit https://github.com/faucetsdn/ryu/wiki/OpenStack .
For more information, please visit http://github.com/osrg/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 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.
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.
Writing Ryu applications is easy. They're just Python scripts.
Writing Ryu application is easy. It's just Python scripts.
Start Writing
=============
Here we show a Ryu application that makes an OpenFlow switch work as a dumb
We show a Ryu application that make OpenFlow switches work as a dumb
layer 2 switch.
Open a text editor and create a new file with the following content:
Open a text editor creating a new file with the following content:
.. code-block:: python
@ -29,9 +29,9 @@ Open a text editor and create a new file with the following content:
def __init__(self, *args, **kwargs):
super(L2Switch, self).__init__(*args, **kwargs)
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.
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.
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 define a new subclass of RyuApp to run
All you have to do is defining needs a new subclass of RyuApp to run
your Python script as a Ryu application.
Next let's add some functionality that sends a received packet to all
Next let's add the functionality of sending a received packet to all
the ports.
.. code-block:: python
@ -53,11 +53,8 @@ the ports.
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_0
class L2Switch(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION]
def __init__(self, *args, **kwargs):
super(L2Switch, self).__init__(*args, **kwargs)
@ -67,31 +64,26 @@ 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, data = data)
actions=actions)
dp.send_msg(out)
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
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
'set_ev_cls' decorator. This decorator tells Ryu when the decorated
function should be called.
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
The first argument of the decorator indicates an event that makes
function called. As you expect easily, every time Ryu gets a
packet_in message, this function is called.
The second argument indicates the state of the switch. You probably
The second argument indicates the state of the switch. Probably, you
want to ignore packet_in messages before the negotiation between Ryu
and the switch is finished. Using 'MAIN_DISPATCHER' as the second
and the switch finishes. Using 'MAIN_DISPATCHER' as the second
argument means this function is called only after the negotiation
completes.
@ -108,24 +100,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 uses the OFPP_FLOOD flag to indicate that the packet should
be sent out on all ports.
application need a switch to send out of all the ports so OFPP_FLOOD
constant is used.
* 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 sends the on-wire data format to the switch.
class object, Ryu builds and send the on-wire data format to the switch.
There, you finished implementing your first Ryu application. You are ready to
run a Ryu application that does something useful.
Here, you finished implementing your first Ryu application. You are ready to
run this Ryu application that does something useful.
Is a dumb L2 switch is too dumb? You want to implement a learning L2
A dumb l2 switch is too dumb? You want to implement a learning l2
switch? Move to `the next step
<https://github.com/faucetsdn/ryu/blob/master/ryu/app/simple_switch.py>`_. You
<https://github.com/osrg/ryu/blob/master/ryu/app/simple_switch.py>`_. You
can learn from the existing Ryu applications at `ryu/app
<https://github.com/faucetsdn/ryu/blob/master/ryu/app/>`_ directory and
<https://github.com/osrg/ryu/blob/master/ryu/app/>`_ directory and
`integrated tests
<https://github.com/faucetsdn/ryu/blob/master/ryu/tests/integrated/>`_
<https://github.com/osrg/ryu/blob/master/ryu/tests/integrated/>`_
directory.

View File

@ -1 +0,0 @@
pip==20.3.4

View File

@ -8,16 +8,16 @@ usage() {
echo "Usage: $0 [OPTION]..."
echo "Run Ryu's test suite(s)"
echo ""
echo " -V, --virtual-env Always use virtualenv. Install automatically if not present"
echo " -N, --no-virtual-env Don't use virtualenv. Run tests in local environment"
echo " -c, --coverage Generate coverage report"
echo " -f, --force Force a clean re-build of the virtual environment. Useful when dependencies have been added."
echo " -p, --pycodestyle, --pep8 Just run pycodestyle(pep8)"
echo " -P, --no-pycodestyle, --no-pep8 Don't run pycodestyle(pep8)"
echo " -l, --pylint Just run pylint"
echo " -i, --integrated Run integrated test"
echo " -v, --verbose Run verbose pylint analysis"
echo " -h, --help Print this usage message"
echo " -V, --virtual-env Always use virtualenv. Install automatically if not present"
echo " -N, --no-virtual-env Don't use virtualenv. Run tests in local environment"
echo " -c, --coverage Generate coverage report"
echo " -f, --force Force a clean re-build of the virtual environment. Useful when dependencies have been added."
echo " -p, --pep8 Just run pep8"
echo " -P, --no-pep8 Don't run pep8"
echo " -l, --pylint Just run pylint"
echo " -i, --integrated Run integrated test"
echo " -v, --verbose Run verbose pylint analysis"
echo " -h, --help Print this usage message"
echo ""
echo "Note: with no options specified, the script will try to run the tests in a virtual environment,"
echo " If no virtualenv is found, the script will ask if you would like to create one. If you "
@ -31,8 +31,8 @@ process_option() {
-V|--virtual-env) always_venv=1; never_venv=0;;
-N|--no-virtual-env) always_venv=0; never_venv=1;;
-f|--force) force=1;;
-p|--pycodestyle|--pep8) just_pycodestyle=1; never_venv=1; always_venv=0;;
-P|--no-pycodestyle|--no-pep8) no_pycodestyle=1;;
-p|--pep8) just_pep8=1; never_venv=1; always_venv=0;;
-P|--no-pep8) no_pep8=1;;
-l|--pylint) just_pylint=1;;
-i|--integrated) integrated=1;;
-c|--coverage) coverage=1;;
@ -46,8 +46,8 @@ venv=.venv
with_venv=tools/with_venv.sh
always_venv=0
never_venv=0
just_pycodestyle=0
no_pycodestyle=0
just_pep8=0
no_pep8=0
just_pylint=0
integrated=0
force=0
@ -103,26 +103,20 @@ run_pylint() {
export PYTHONPATH=$OLD_PYTHONPATH
}
run_pycodestyle() {
PYCODESTYLE=$(which pycodestyle || which pep8)
if [ -z "${PYCODESTYLE}" ]
then
echo "Please install pycodestyle or pep8"
return 1
fi
echo "Running $(basename ${PYCODESTYLE}) ..."
run_pep8() {
echo "Running pep8 ..."
PYCODESTYLE_OPTIONS="--repeat --show-source"
PYCODESTYLE_INCLUDE="ryu setup*.py"
PYCODESTYLE_LOG=pycodestyle.log
${wrapper} ${PYCODESTYLE} $PYCODESTYLE_OPTIONS $PYCODESTYLE_INCLUDE | tee $PYCODESTYLE_LOG
PEP8_OPTIONS="--repeat --show-source"
PEP8_INCLUDE="ryu setup*.py"
PEP8_LOG=pep8.log
${wrapper} pep8 $PEP8_OPTIONS $PEP8_INCLUDE | tee $PEP8_LOG
}
run_integrated() {
echo "Running integrated test ..."
INTEGRATED_TEST_RUNNER="./ryu/tests/integrated/run_tests_with_ovs12.py"
sudo PYTHONPATH=. nosetests -s $INTEGRATED_TEST_RUNNER
sudo PYTHONPATH=. nosetests -s $INTEGRATED_TEST_RUNNER
}
#NOSETESTS="nosetests $noseopts $noseargs"
NOSETESTS="${PYTHON} ./ryu/tests/run_tests.py $noseopts $noseargs"
@ -167,8 +161,8 @@ if [ $coverage -eq 1 ]; then
${wrapper} coverage erase
fi
if [ $just_pycodestyle -eq 1 ]; then
run_pycodestyle
if [ $just_pep8 -eq 1 ]; then
run_pep8
exit
fi
if [ $just_pylint -eq 1 ]; then
@ -183,8 +177,8 @@ fi
run_tests
RV=$?
if [ $no_pycodestyle -eq 0 ]; then
run_pycodestyle
if [ $no_pep8 -eq 0 ]; then
run_pep8
fi
if [ $coverage -eq 1 ]; then

View File

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

View File

@ -1,101 +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.
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
class ExampleSwitch13(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
def __init__(self, *args, **kwargs):
super(ExampleSwitch13, self).__init__(*args, **kwargs)
# initialize mac address table.
self.mac_to_port = {}
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
datapath = ev.msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
# install the table-miss flow entry.
match = parser.OFPMatch()
actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath, 0, match, actions)
def add_flow(self, datapath, priority, match, actions):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
# construct flow_mod message and send it.
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
match=match, instructions=inst)
datapath.send_msg(mod)
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
# get Datapath ID to identify OpenFlow switches.
dpid = datapath.id
self.mac_to_port.setdefault(dpid, {})
# analyse the received packets using the packet library.
pkt = packet.Packet(msg.data)
eth_pkt = pkt.get_protocol(ethernet.ethernet)
dst = eth_pkt.dst
src = eth_pkt.src
# get the received port number from packet_in message.
in_port = msg.match['in_port']
self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
# learn a mac address to avoid FLOOD next time.
self.mac_to_port[dpid][src] = in_port
# if the destination mac address is already learned,
# decide which port to output the packet, otherwise FLOOD.
if dst in self.mac_to_port[dpid]:
out_port = self.mac_to_port[dpid][dst]
else:
out_port = ofproto.OFPP_FLOOD
# construct action list.
actions = [parser.OFPActionOutput(out_port)]
# install a flow to avoid packet_in next time.
if out_port != ofproto.OFPP_FLOOD:
match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
self.add_flow(datapath, 1, match, actions)
# construct packet_out message and send it.
out = parser.OFPPacketOut(datapath=datapath,
buffer_id=ofproto.OFP_NO_BUFFER,
in_port=in_port, actions=actions,
data=msg.data)
datapath.send_msg(out)

View File

@ -56,7 +56,7 @@ class GUIServerController(ControllerBase):
path = "%s/html/" % PATH
self.static_app = DirectoryApp(path)
@route('topology', '/{filename:[^/]*}')
@route('topology', '/{filename:.*}')
def static_handler(self, req, **kwargs):
if kwargs['filename']:
req.path_info = kwargs['filename']

View File

@ -16,37 +16,22 @@
# client for ryu.app.ofctl.service
import numbers
from ryu.base import app_manager
from . import event
def get_datapath(app, dpid=None):
def get_datapath(app, dpid):
"""
Get datapath object by dpid.
:param app: Client RyuApp instance
:param dpid: Datapath ID (int type) or None to get all datapath objects
:param dpid: Datapath-id (in integer)
Returns a object of datapath, a list of datapath objects when no dpid
given or None when error.
Raises an exception if any of the given values is invalid.
Example::
# ...(snip)...
import ryu.app.ofctl.api as ofctl_api
class MyApp(app_manager.RyuApp):
def _my_handler(self, ev):
# Get all datapath objects
result = ofctl_api.get_datapath(self)
# Get the datapath object which has the given dpid
result = ofctl_api.get_datapath(self, dpid=1)
Returns None on error.
"""
assert isinstance(dpid, numbers.Integral)
return app.send_request(event.GetDatapathRequest(dpid=dpid))()
@ -70,19 +55,12 @@ def send_msg(app, msg, reply_cls=None, reply_multi=False):
Example::
# ...(snip)...
import ryu.app.ofctl.api as ofctl_api
import ryu.app.ofctl.api as api
class MyApp(app_manager.RyuApp):
def _my_handler(self, ev):
# ...(snip)...
msg = parser.OFPPortDescStatsRequest(datapath=datapath)
result = ofctl_api.send_msg(
self, msg,
reply_cls=parser.OFPPortDescStatsReply,
reply_multi=True)
msg = parser.OFPPortDescStatsRequest(datapath=datapath)
result = api.send_msg(self, msg,
reply_cls=parser.OFPPortDescStatsReply,
reply_multi=True)
"""
return app.send_request(event.SendMsgRequest(msg=msg,
reply_cls=reply_cls,

View File

@ -33,8 +33,8 @@ class _ReplyBase(event.EventReplyBase):
# get datapath
class GetDatapathRequest(_RequestBase):
def __init__(self, dpid=None):
assert dpid is None or isinstance(dpid, numbers.Integral)
def __init__(self, dpid):
assert isinstance(dpid, numbers.Integral)
super(GetDatapathRequest, self).__init__()
self.dpid = dpid

View File

@ -64,22 +64,6 @@ 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)) ==
@ -95,11 +79,6 @@ class OfctlService(app_manager.RyuApp):
self.logger.debug('add dpid %s datapath %s new_info %s old_info %s',
id, datapath, new_info, old_info)
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):
@ -115,25 +94,23 @@ 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):
result = None
if req.dpid is None:
result = [v.datapath for v in self._switches.values()]
else:
if req.dpid in self._switches:
result = self._switches[req.dpid].datapath
self.reply_to_request(req, event.Reply(result=result))
id = req.dpid
assert isinstance(id, numbers.Integral)
try:
datapath = self._switches[id].datapath
except KeyError:
datapath = None
self.logger.debug('dpid %s -> datapath %s', id, datapath)
rep = event.Reply(result=datapath)
self.reply_to_request(req, rep)
@set_ev_cls(event.SendMsgRequest, MAIN_DISPATCHER)
def _handle_send_msg(self, req):
msg = req.msg
datapath = msg.datapath
parser = datapath.ofproto_parser
is_barrier = isinstance(msg, parser.OFPBarrierRequest)
try:
si = self._switches[datapath.id]
@ -144,40 +121,28 @@ class OfctlService(app_manager.RyuApp):
self.reply_to_request(req, rep)
return
def _store_xid(xid, barrier_xid):
assert xid not in si.results
assert xid not in si.xids
assert barrier_xid not in si.barriers
si.results[xid] = []
si.xids[xid] = req
si.barriers[barrier_xid] = xid
if req.reply_cls is not None:
self._observe_msg(req.reply_cls)
if is_barrier:
barrier = msg
datapath.set_xid(barrier)
_store_xid(barrier.xid, barrier.xid)
else:
if req.reply_cls is not None:
self._observe_msg(req.reply_cls)
datapath.set_xid(msg)
barrier = datapath.ofproto_parser.OFPBarrierRequest(datapath)
datapath.set_xid(barrier)
_store_xid(msg.xid, barrier.xid)
if not datapath.send_msg(msg):
return self._cancel(
si, barrier.xid,
exception.InvalidDatapath(result=datapath.id))
datapath.set_xid(msg)
xid = msg.xid
barrier = datapath.ofproto_parser.OFPBarrierRequest(datapath)
datapath.set_xid(barrier)
barrier_xid = barrier.xid
assert xid not in si.results
assert xid not in si.xids
assert barrier_xid not in si.barriers
si.results[xid] = []
si.xids[xid] = req
si.barriers[barrier_xid] = xid
if not datapath.send_msg(barrier):
return self._cancel(
si, barrier.xid,
exception.InvalidDatapath(result=datapath.id))
datapath.send_msg(msg)
datapath.send_msg(barrier)
@set_ev_cls(ofp_event.EventOFPBarrierReply, MAIN_DISPATCHER)
def _handle_barrier(self, ev):
msg = ev.msg
datapath = msg.datapath
parser = datapath.ofproto_parser
try:
si = self._switches[datapath.id]
except KeyError:
@ -190,12 +155,9 @@ class OfctlService(app_manager.RyuApp):
return
result = si.results.pop(xid)
req = si.xids.pop(xid)
is_barrier = isinstance(req.msg, parser.OFPBarrierRequest)
if req.reply_cls is not None and not is_barrier:
if req.reply_cls is not None:
self._unobserve_msg(req.reply_cls)
if is_barrier and req.reply_cls == parser.OFPBarrierReply:
rep = event.Reply(result=ev.msg)
elif any(self._is_error(r) for r in result):
if any(self._is_error(r) for r in result):
rep = event.Reply(exception=exception.OFError(result=result))
elif req.reply_multi:
rep = event.Reply(result=result)
@ -223,7 +185,7 @@ class OfctlService(app_manager.RyuApp):
self.logger.error('unknown error xid %s', msg.xid)
return
if ((not isinstance(ev, ofp_event.EventOFPErrorMsg)) and
(req.reply_cls is None or not isinstance(ev.msg, req.reply_cls))):
(req.reply_cls is None or not isinstance(ev.msg, req.reply_cls))):
self.logger.error('unexpected reply %s for xid %s', ev, msg.xid)
return
try:

File diff suppressed because it is too large Load Diff

View File

@ -21,12 +21,12 @@ This module provides a set of REST API for switch configuration.
Used by OpenStack Ryu agent.
"""
import json
from six.moves import http_client
import json
import logging
from webob import Response
from ryu.app.wsgi import ControllerBase
from ryu.app.wsgi import Response
from ryu.base import app_manager
from ryu.controller import conf_switch
from ryu.lib import dpid as dpid_lib
@ -111,11 +111,7 @@ class ConfSwitchController(ControllerBase):
def set_key(self, req, dpid, key, **_kwargs):
def _set_val(dpid, key):
try:
val = req.json if req.body else {}
except ValueError:
return Response(status=http_client.BAD_REQUEST,
body='invalid syntax %s' % req.body)
val = json.loads(req.body)
self.conf_switch.set_key(dpid, key, val)
return None

View File

@ -17,8 +17,9 @@
import logging
import json
from webob import Response
from ryu.app.wsgi import ControllerBase
from ryu.app.wsgi import Response
from ryu.app.wsgi import WSGIApplication
from ryu.base import app_manager
from ryu.controller import ofp_event
@ -491,8 +492,8 @@ class FirewallController(ControllerBase):
def _set_rule(self, req, switchid, vlan_id=VLANID_NONE):
try:
rule = req.json if req.body else {}
except ValueError:
rule = json.loads(req.body)
except SyntaxError:
FirewallController._LOGGER.debug('invalid syntax %s', req.body)
return Response(status=400)
@ -515,8 +516,8 @@ class FirewallController(ControllerBase):
def _delete_rule(self, req, switchid, vlan_id=VLANID_NONE):
try:
ruleid = req.json if req.body else {}
except ValueError:
ruleid = json.loads(req.body)
except SyntaxError:
FirewallController._LOGGER.debug('invalid syntax %s', req.body)
return Response(status=400)
@ -678,7 +679,8 @@ class Firewall(object):
def _set_log_status(self, is_enable, waiters):
if is_enable:
actions = Action.to_openflow({REST_ACTION: REST_ACTION_PACKETIN})
actions = Action.to_openflow(self.dp,
{REST_ACTION: REST_ACTION_PACKETIN})
details = 'Log collection started.'
else:
actions = []
@ -720,7 +722,7 @@ class Firewall(object):
priority = ARP_FLOW_PRIORITY
match = {REST_DL_TYPE: ether.ETH_TYPE_ARP}
action = {REST_ACTION: REST_ACTION_ALLOW}
actions = Action.to_openflow(action)
actions = Action.to_openflow(self.dp, action)
flow = self._to_of_flow(cookie=cookie, priority=priority,
match=match, actions=actions)
@ -752,7 +754,7 @@ class Firewall(object):
result = self.get_log_status(waiters)
if result[REST_LOG_STATUS] == REST_STATUS_ENABLE:
rest[REST_ACTION] = REST_ACTION_PACKETIN
actions = Action.to_openflow(rest)
actions = Action.to_openflow(self.dp, rest)
flow = self._to_of_flow(cookie=cookie, priority=priority,
match=match, actions=actions)
@ -879,7 +881,7 @@ class Firewall(object):
rule = {REST_RULE_ID: ruleid}
rule.update({REST_PRIORITY: flow[REST_PRIORITY]})
rule.update(Match.to_rest(flow))
rule.update(Action.to_rest(flow))
rule.update(Action.to_rest(self.dp, flow))
return rule
@ -1077,17 +1079,19 @@ class Match(object):
class Action(object):
@staticmethod
def to_openflow(rest):
def to_openflow(dp, rest):
value = rest.get(REST_ACTION, REST_ACTION_ALLOW)
if value == REST_ACTION_ALLOW:
out_port = dp.ofproto.OFPP_NORMAL
action = [{'type': 'OUTPUT',
'port': 'NORMAL'}]
'port': out_port}]
elif value == REST_ACTION_DENY:
action = []
elif value == REST_ACTION_PACKETIN:
out_port = dp.ofproto.OFPP_CONTROLLER
action = [{'type': 'OUTPUT',
'port': 'CONTROLLER',
'port': out_port,
'max_len': 128}]
else:
raise ValueError('Invalid action type.')
@ -1095,9 +1099,9 @@ class Action(object):
return action
@staticmethod
def to_rest(openflow):
def to_rest(dp, openflow):
if REST_ACTION in openflow:
action_allow = 'OUTPUT:NORMAL'
action_allow = 'OUTPUT:%d' % dp.ofproto.OFPP_NORMAL
if openflow[REST_ACTION] == [action_allow]:
action = {REST_ACTION: REST_ACTION_ALLOW}
else:

View File

@ -18,11 +18,10 @@ import logging
import json
import re
from webob import Response
from ryu.app import conf_switch_key as cs_key
from ryu.app.wsgi import ControllerBase
from ryu.app.wsgi import Response
from ryu.app.wsgi import route
from ryu.app.wsgi import WSGIApplication
from ryu.app.wsgi import ControllerBase, WSGIApplication, route
from ryu.base import app_manager
from ryu.controller import conf_switch
from ryu.controller import ofp_event
@ -425,8 +424,7 @@ class QoSController(ControllerBase):
@staticmethod
def delete_ovsdb_addr(dpid):
ofs = QoSController._OFS_LIST.get(dpid, None)
if ofs is not None:
ofs.set_ovsdb_addr(dpid, None)
ofs.set_ovsdb_addr(dpid, None)
@route('qos_switch', BASE_URL + '/queue/{switchid}',
methods=['GET'], requirements=REQUIREMENTS)
@ -508,8 +506,8 @@ class QoSController(ControllerBase):
def _access_switch(self, req, switchid, vlan_id, func, waiters):
try:
rest = req.json if req.body else {}
except ValueError:
rest = json.loads(req.body) if req.body else {}
except SyntaxError:
QoSController._LOGGER.debug('invalid syntax %s', req.body)
return Response(status=400)
@ -558,22 +556,6 @@ class QoS(object):
self.vlan_list[VLANID_NONE] = 0 # for VLAN=None
self.dp = dp
self.version = dp.ofproto.OFP_VERSION
# Dictionary of port name to Queue config.
# e.g.)
# self.queue_list = {
# "s1-eth1": {
# "0": {
# "config": {
# "max-rate": "600000"
# }
# },
# "1": {
# "config": {
# "min-rate": "900000"
# }
# }
# }
# }
self.queue_list = {}
self.CONF = CONF
self.ovsdb_addr = None
@ -601,22 +583,25 @@ class QoS(object):
self.ofctl.mod_flow_entry(self.dp, flow, cmd)
def set_ovsdb_addr(self, dpid, ovsdb_addr):
# easy check if the address format valid
_proto, _host, _port = ovsdb_addr.split(':')
old_address = self.ovsdb_addr
if old_address == ovsdb_addr:
return
elif ovsdb_addr is None:
# Determine deleting OVSDB address was requested.
if ovsdb_addr is None:
if self.ovs_bridge:
self.ovs_bridge.del_controller()
self.ovs_bridge = None
return
ovs_bridge = bridge.OVSBridge(self.CONF, dpid, ovsdb_addr)
try:
ovs_bridge.init()
except:
raise ValueError('ovsdb addr is not available.')
self.ovsdb_addr = ovsdb_addr
self.ovs_bridge = ovs_bridge
if self.ovs_bridge is None:
ovs_bridge = bridge.OVSBridge(self.CONF, dpid, ovsdb_addr)
self.ovs_bridge = ovs_bridge
try:
ovs_bridge.init()
except:
raise ValueError('ovsdb addr is not available.')
def _update_vlan_list(self, vlan_list):
for vlan_id in self.vlan_list.keys():
@ -679,15 +664,7 @@ class QoS(object):
'details': 'ovs_bridge is not exists'}
return REST_COMMAND_RESULT, msg
port_name = rest.get(REST_PORT_NAME, None)
vif_ports = self.ovs_bridge.get_port_name_list()
if port_name is not None:
if port_name not in vif_ports:
raise ValueError('%s port is not exists' % port_name)
vif_ports = [port_name]
queue_list = {}
self.queue_list.clear()
queue_type = rest.get(REST_QUEUE_TYPE, 'linux-htb')
parent_max_rate = rest.get(REST_QUEUE_MAX_RATE, None)
queues = rest.get(REST_QUEUES, [])
@ -705,9 +682,17 @@ class QoS(object):
config['min-rate'] = min_rate
if len(config):
queue_config.append(config)
queue_list[queue_id] = {'config': config}
self.queue_list[queue_id] = {'config': config}
queue_id += 1
port_name = rest.get(REST_PORT_NAME, None)
vif_ports = self.ovs_bridge.get_port_name_list()
if port_name is not None:
if port_name not in vif_ports:
raise ValueError('%s port is not exists' % port_name)
vif_ports = [port_name]
for port_name in vif_ports:
try:
self.ovs_bridge.set_qos(port_name, type=queue_type,
@ -715,10 +700,9 @@ class QoS(object):
queues=queue_config)
except Exception as msg:
raise ValueError(msg)
self.queue_list[port_name] = queue_list
msg = {'result': 'success',
'details': queue_list}
'details': self.queue_list}
return REST_COMMAND_RESULT, msg
@ -733,9 +717,9 @@ class QoS(object):
@rest_command
def delete_queue(self, rest, vlan_id):
self.queue_list.clear()
if self._delete_queue():
msg = 'success'
self.queue_list.clear()
else:
msg = 'failure'
@ -1143,20 +1127,20 @@ class Match(object):
class Action(object):
@staticmethod
def to_rest(flow):
if REST_ACTION in flow:
def to_rest(openflow):
if REST_ACTION in openflow:
actions = []
for act in flow[REST_ACTION]:
field_value = re.search(r'SET_FIELD: \{ip_dscp:(\d+)', act)
for action in openflow[REST_ACTION]:
field_value = re.search('SET_FIELD: {ip_dscp:(\d+)', action)
if field_value:
actions.append({REST_ACTION_MARK: field_value.group(1)})
meter_value = re.search(r'METER:(\d+)', act)
meter_value = re.search('METER:(\d+)', action)
if meter_value:
actions.append({REST_ACTION_METER: meter_value.group(1)})
queue_value = re.search(r'SET_QUEUE:(\d+)', act)
queue_value = re.search('SET_QUEUE:(\d+)', action)
if queue_value:
actions.append({REST_ACTION_QUEUE: queue_value.group(1)})
action = {REST_ACTION: actions}
action = {REST_ACTION: actions}
else:
action = {REST_ACTION: 'Unknown action type.'}

View File

@ -20,9 +20,9 @@ import socket
import struct
import json
from webob import Response
from ryu.app.wsgi import ControllerBase
from ryu.app.wsgi import Response
from ryu.app.wsgi import WSGIApplication
from ryu.base import app_manager
from ryu.controller import dpset
@ -40,7 +40,6 @@ from ryu.lib.packet import ethernet
from ryu.lib.packet import icmp
from ryu.lib.packet import ipv4
from ryu.lib.packet import packet
from ryu.lib.packet import packet_base
from ryu.lib.packet import tcp
from ryu.lib.packet import udp
from ryu.lib.packet import vlan
@ -377,45 +376,42 @@ class RouterController(ControllerBase):
@rest_command
def get_data(self, req, switch_id, **_kwargs):
return self._access_router(switch_id, VLANID_NONE,
'get_data', req)
'get_data', req.body)
# GET /router/{switch_id}/{vlan_id}
@rest_command
def get_vlan_data(self, req, switch_id, vlan_id, **_kwargs):
return self._access_router(switch_id, vlan_id,
'get_data', req)
'get_data', req.body)
# POST /router/{switch_id}
@rest_command
def set_data(self, req, switch_id, **_kwargs):
return self._access_router(switch_id, VLANID_NONE,
'set_data', req)
'set_data', req.body)
# POST /router/{switch_id}/{vlan_id}
@rest_command
def set_vlan_data(self, req, switch_id, vlan_id, **_kwargs):
return self._access_router(switch_id, vlan_id,
'set_data', req)
'set_data', req.body)
# DELETE /router/{switch_id}
@rest_command
def delete_data(self, req, switch_id, **_kwargs):
return self._access_router(switch_id, VLANID_NONE,
'delete_data', req)
'delete_data', req.body)
# DELETE /router/{switch_id}/{vlan_id}
@rest_command
def delete_vlan_data(self, req, switch_id, vlan_id, **_kwargs):
return self._access_router(switch_id, vlan_id,
'delete_data', req)
'delete_data', req.body)
def _access_router(self, switch_id, vlan_id, func, req):
def _access_router(self, switch_id, vlan_id, func, rest_param):
rest_message = []
routers = self._get_router(switch_id)
try:
param = req.json if req.body else {}
except ValueError:
raise SyntaxError('invalid syntax %s', req.body)
param = json.loads(rest_param) if rest_param else {}
for router in routers.values():
function = getattr(router, func)
data = function(vlan_id, param, self.waiters)
@ -570,8 +566,7 @@ class Router(dict):
# TODO: Packet library convert to string
# self.logger.debug('Packet in = %s', str(pkt), self.sw_id)
header_list = dict((p.protocol_name, p)
for p in pkt.protocols
if isinstance(p, packet_base.PacketBase))
for p in pkt.protocols if type(p) != str)
if header_list:
# Check vlan-tag
vlan_id = VLANID_NONE
@ -1010,14 +1005,14 @@ class VlanRouter(object):
else:
if header_list[ARP].opcode == arp.ARP_REQUEST:
# ARP request to router port -> send ARP reply
src_mac = self.port_data[in_port].mac
dst_mac = header_list[ARP].src_mac
src_mac = header_list[ARP].src_mac
dst_mac = self.port_data[in_port].mac
arp_target_mac = dst_mac
output = in_port
in_port = self.ofctl.dp.ofproto.OFPP_CONTROLLER
self.ofctl.send_arp(arp.ARP_REPLY, self.vlan_id,
src_mac, dst_mac, dst_ip, src_ip,
dst_mac, src_mac, dst_ip, src_ip,
arp_target_mac, in_port, output)
log_msg = 'Receive ARP request from [%s] to router port [%s].'
@ -1528,37 +1523,18 @@ class OfCtl(object):
eth = protocol_list[ETHERNET]
e = ethernet.ethernet(eth.src, eth.dst, ether_proto)
ip = protocol_list[IPV4]
if icmp_data is None and msg_data is not None:
# RFC 4884 says that we should send "at least 128 octets"
# if we are using the ICMP Extension Structure.
# We're not using the extension structure, but let's send
# up to 128 bytes of the original msg_data.
#
# RFC 4884 also states that the length field is interpreted in
# 32 bit units, so the length calculated in bytes needs to first
# be divided by 4, then increased by 1 if the modulus is non-zero.
#
# Finally, RFC 4884 says, if we're specifying the length, we MUST
# zero pad to the next 32 bit boundary.
end_of_data = offset + len(ip) + 128
ip_datagram = bytearray()
ip_datagram += msg_data[offset:end_of_data]
data_len = int(len(ip_datagram) / 4)
length_modulus = int(len(ip_datagram) % 4)
if length_modulus:
data_len += 1
ip_datagram += bytearray([0] * (4 - length_modulus))
ip_datagram = msg_data[offset:]
if icmp_type == icmp.ICMP_DEST_UNREACH:
icmp_data = icmp.dest_unreach(data_len=data_len,
icmp_data = icmp.dest_unreach(data_len=len(ip_datagram),
data=ip_datagram)
elif icmp_type == icmp.ICMP_TIME_EXCEEDED:
icmp_data = icmp.TimeExceeded(data_len=data_len,
icmp_data = icmp.TimeExceeded(data_len=len(ip_datagram),
data=ip_datagram)
ic = icmp.icmp(icmp_type, icmp_code, csum, data=icmp_data)
ip = protocol_list[IPV4]
if src_ip is None:
src_ip = ip.dst
ip_total_length = ip.header_length * 4 + ic._MIN_LEN

View File

@ -14,11 +14,9 @@
# limitations under the License.
import json
from webob import Response
from ryu.app.wsgi import ControllerBase
from ryu.app.wsgi import Response
from ryu.app.wsgi import route
from ryu.app.wsgi import WSGIApplication
from ryu.app.wsgi import ControllerBase, WSGIApplication, route
from ryu.base import app_manager
from ryu.lib import dpid as dpid_lib
from ryu.topology.api import get_switch, get_link, get_host

File diff suppressed because it is too large Load Diff

View File

@ -1,95 +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.
from operator import attrgetter
from ryu.app import simple_switch_13
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER, DEAD_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.lib import hub
class SimpleMonitor13(simple_switch_13.SimpleSwitch13):
def __init__(self, *args, **kwargs):
super(SimpleMonitor13, self).__init__(*args, **kwargs)
self.datapaths = {}
self.monitor_thread = hub.spawn(self._monitor)
@set_ev_cls(ofp_event.EventOFPStateChange,
[MAIN_DISPATCHER, DEAD_DISPATCHER])
def _state_change_handler(self, ev):
datapath = ev.datapath
if ev.state == MAIN_DISPATCHER:
if datapath.id not in self.datapaths:
self.logger.debug('register datapath: %016x', datapath.id)
self.datapaths[datapath.id] = datapath
elif ev.state == DEAD_DISPATCHER:
if datapath.id in self.datapaths:
self.logger.debug('unregister datapath: %016x', datapath.id)
del self.datapaths[datapath.id]
def _monitor(self):
while True:
for dp in self.datapaths.values():
self._request_stats(dp)
hub.sleep(10)
def _request_stats(self, datapath):
self.logger.debug('send stats request: %016x', datapath.id)
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
req = parser.OFPFlowStatsRequest(datapath)
datapath.send_msg(req)
req = parser.OFPPortStatsRequest(datapath, 0, ofproto.OFPP_ANY)
datapath.send_msg(req)
@set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
def _flow_stats_reply_handler(self, ev):
body = ev.msg.body
self.logger.info('datapath '
'in-port eth-dst '
'out-port packets bytes')
self.logger.info('---------------- '
'-------- ----------------- '
'-------- -------- --------')
for stat in sorted([flow for flow in body if flow.priority == 1],
key=lambda flow: (flow.match['in_port'],
flow.match['eth_dst'])):
self.logger.info('%016x %8x %17s %8x %8d %8d',
ev.msg.datapath.id,
stat.match['in_port'], stat.match['eth_dst'],
stat.instructions[0].actions[0].port,
stat.packet_count, stat.byte_count)
@set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
def _port_stats_reply_handler(self, ev):
body = ev.msg.body
self.logger.info('datapath port '
'rx-pkts rx-bytes rx-error '
'tx-pkts tx-bytes tx-error')
self.logger.info('---------------- -------- '
'-------- -------- -------- '
'-------- -------- --------')
for stat in sorted(body, key=attrgetter('port_no')):
self.logger.info('%016x %8x %8d %8d %8d %8d %8d %8d',
ev.msg.datapath.id, stat.port_no,
stat.rx_packets, stat.rx_bytes, stat.rx_errors,
stat.tx_packets, stat.tx_bytes, stat.tx_errors)

View File

@ -36,12 +36,11 @@ class SimpleSwitch(app_manager.RyuApp):
super(SimpleSwitch, self).__init__(*args, **kwargs)
self.mac_to_port = {}
def add_flow(self, datapath, in_port, dst, src, actions):
def add_flow(self, datapath, in_port, dst, actions):
ofproto = datapath.ofproto
match = datapath.ofproto_parser.OFPMatch(
in_port=in_port,
dl_dst=haddr_to_bin(dst), dl_src=haddr_to_bin(src))
in_port=in_port, dl_dst=haddr_to_bin(dst))
mod = datapath.ofproto_parser.OFPFlowMod(
datapath=datapath, match=match, cookie=0,
@ -82,7 +81,7 @@ class SimpleSwitch(app_manager.RyuApp):
# install a flow to avoid packet_in next time
if out_port != ofproto.OFPP_FLOOD:
self.add_flow(datapath, msg.in_port, dst, src, actions)
self.add_flow(datapath, msg.in_port, dst, actions)
data = None
if msg.buffer_id == ofproto.OFP_NO_BUFFER:

View File

@ -30,12 +30,11 @@ class SimpleSwitch12(app_manager.RyuApp):
super(SimpleSwitch12, self).__init__(*args, **kwargs)
self.mac_to_port = {}
def add_flow(self, datapath, port, dst, src, actions):
def add_flow(self, datapath, port, dst, actions):
ofproto = datapath.ofproto
match = datapath.ofproto_parser.OFPMatch(in_port=port,
eth_dst=dst,
eth_src=src)
eth_dst=dst)
inst = [datapath.ofproto_parser.OFPInstructionActions(
ofproto.OFPIT_APPLY_ACTIONS, actions)]
@ -81,7 +80,7 @@ class SimpleSwitch12(app_manager.RyuApp):
# install a flow to avoid packet_in next time
if out_port != ofproto.OFPP_FLOOD:
self.add_flow(datapath, in_port, dst, src, actions)
self.add_flow(datapath, in_port, dst, actions)
data = None
if msg.buffer_id == ofproto.OFP_NO_BUFFER:

View File

@ -85,7 +85,7 @@ class SimpleSwitch13(app_manager.RyuApp):
dst = eth.dst
src = eth.src
dpid = format(datapath.id, "d").zfill(16)
dpid = datapath.id
self.mac_to_port.setdefault(dpid, {})
self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
@ -102,7 +102,7 @@ class SimpleSwitch13(app_manager.RyuApp):
# install a flow to avoid packet_in next time
if out_port != ofproto.OFPP_FLOOD:
match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src)
match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
# verify if we have a valid buffer_id, if yes avoid to send both
# flow_mod & packet_out
if msg.buffer_id != ofproto.OFP_NO_BUFFER:

View File

@ -93,7 +93,7 @@ class SimpleSwitch14(app_manager.RyuApp):
# install a flow to avoid packet_in next time
if out_port != ofproto.OFPP_FLOOD:
match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src)
match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
self.add_flow(datapath, 1, match, actions)
data = None

View File

@ -1,107 +0,0 @@
# Copyright (C) 2011 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.
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_5
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.lib.packet import ether_types
class SimpleSwitch15(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_5.OFP_VERSION]
def __init__(self, *args, **kwargs):
super(SimpleSwitch15, self).__init__(*args, **kwargs)
self.mac_to_port = {}
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
datapath = ev.msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
# install table-miss flow entry
#
# We specify NO BUFFER to max_len of the output action due to
# OVS bug. At this moment, if we specify a lesser number, e.g.,
# 128, OVS will send Packet-In with invalid buffer_id and
# truncated packet data. In that case, we cannot output packets
# correctly. The bug has been fixed in OVS v2.1.0.
match = parser.OFPMatch()
actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath, 0, match, actions)
def add_flow(self, datapath, priority, match, actions):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
match=match, instructions=inst)
datapath.send_msg(mod)
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
in_port = msg.match['in_port']
pkt = packet.Packet(msg.data)
eth = pkt.get_protocols(ethernet.ethernet)[0]
if eth.ethertype == ether_types.ETH_TYPE_LLDP:
# ignore lldp packet
return
dst = eth.dst
src = eth.src
dpid = datapath.id
self.mac_to_port.setdefault(dpid, {})
self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
# learn a mac address to avoid FLOOD next time.
self.mac_to_port[dpid][src] = in_port
if dst in self.mac_to_port[dpid]:
out_port = self.mac_to_port[dpid][dst]
else:
out_port = ofproto.OFPP_FLOOD
actions = [parser.OFPActionOutput(out_port)]
# install a flow to avoid packet_in next time
if out_port != ofproto.OFPP_FLOOD:
match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
self.add_flow(datapath, 1, match, actions)
data = None
if msg.buffer_id == ofproto.OFP_NO_BUFFER:
data = msg.data
match = parser.OFPMatch(in_port=in_port)
out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
match=match, actions=actions, data=data)
datapath.send_msg(out)

View File

@ -1,92 +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.
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib import igmplib
from ryu.lib.dpid import str_to_dpid
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.app import simple_switch_13
class SimpleSwitchIgmp13(simple_switch_13.SimpleSwitch13):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
_CONTEXTS = {'igmplib': igmplib.IgmpLib}
def __init__(self, *args, **kwargs):
super(SimpleSwitchIgmp13, self).__init__(*args, **kwargs)
self.mac_to_port = {}
self._snoop = kwargs['igmplib']
self._snoop.set_querier_mode(
dpid=str_to_dpid('0000000000000001'), server_port=2)
@set_ev_cls(igmplib.EventPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
in_port = msg.match['in_port']
pkt = packet.Packet(msg.data)
eth = pkt.get_protocols(ethernet.ethernet)[0]
dst = eth.dst
src = eth.src
dpid = datapath.id
self.mac_to_port.setdefault(dpid, {})
self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
# learn a mac address to avoid FLOOD next time.
self.mac_to_port[dpid][src] = in_port
if dst in self.mac_to_port[dpid]:
out_port = self.mac_to_port[dpid][dst]
else:
out_port = ofproto.OFPP_FLOOD
actions = [parser.OFPActionOutput(out_port)]
# install a flow to avoid packet_in next time
if out_port != ofproto.OFPP_FLOOD:
match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
self.add_flow(datapath, 1, match, actions)
data = None
if msg.buffer_id == ofproto.OFP_NO_BUFFER:
data = msg.data
out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
in_port=in_port, actions=actions, data=data)
datapath.send_msg(out)
@set_ev_cls(igmplib.EventMulticastGroupStateChanged,
MAIN_DISPATCHER)
def _status_changed(self, ev):
msg = {
igmplib.MG_GROUP_ADDED: 'Multicast Group Added',
igmplib.MG_MEMBER_CHANGED: 'Multicast Group Member Changed',
igmplib.MG_GROUP_REMOVED: 'Multicast Group Removed',
}
self.logger.info("%s: [%s] querier:[%s] hosts:%s",
msg.get(ev.reason), ev.address, ev.src,
ev.dsts)

View File

@ -1,106 +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.
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib import lacplib
from ryu.lib.dpid import str_to_dpid
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.app import simple_switch_13
class SimpleSwitchLacp13(simple_switch_13.SimpleSwitch13):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
_CONTEXTS = {'lacplib': lacplib.LacpLib}
def __init__(self, *args, **kwargs):
super(SimpleSwitchLacp13, self).__init__(*args, **kwargs)
self.mac_to_port = {}
self._lacp = kwargs['lacplib']
self._lacp.add(
dpid=str_to_dpid('0000000000000001'), ports=[1, 2])
def del_flow(self, datapath, match):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
mod = parser.OFPFlowMod(datapath=datapath,
command=ofproto.OFPFC_DELETE,
out_port=ofproto.OFPP_ANY,
out_group=ofproto.OFPG_ANY,
match=match)
datapath.send_msg(mod)
@set_ev_cls(lacplib.EventPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
in_port = msg.match['in_port']
pkt = packet.Packet(msg.data)
eth = pkt.get_protocols(ethernet.ethernet)[0]
dst = eth.dst
src = eth.src
dpid = datapath.id
self.mac_to_port.setdefault(dpid, {})
self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
# learn a mac address to avoid FLOOD next time.
self.mac_to_port[dpid][src] = in_port
if dst in self.mac_to_port[dpid]:
out_port = self.mac_to_port[dpid][dst]
else:
out_port = ofproto.OFPP_FLOOD
actions = [parser.OFPActionOutput(out_port)]
# install a flow to avoid packet_in next time
if out_port != ofproto.OFPP_FLOOD:
match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
self.add_flow(datapath, 1, match, actions)
data = None
if msg.buffer_id == ofproto.OFP_NO_BUFFER:
data = msg.data
out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
in_port=in_port, actions=actions, data=data)
datapath.send_msg(out)
@set_ev_cls(lacplib.EventSlaveStateChanged, MAIN_DISPATCHER)
def _slave_state_changed_handler(self, ev):
datapath = ev.datapath
dpid = datapath.id
port_no = ev.port
enabled = ev.enabled
self.logger.info("slave state changed port: %d enabled: %s",
port_no, enabled)
if dpid in self.mac_to_port:
for mac in self.mac_to_port[dpid]:
match = datapath.ofproto_parser.OFPMatch(eth_dst=mac)
self.del_flow(datapath, match)
del self.mac_to_port[dpid]
self.mac_to_port.setdefault(dpid, {})

View File

@ -1,116 +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 json
from ryu.app import simple_switch_13
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.app.wsgi import ControllerBase
from ryu.app.wsgi import Response
from ryu.app.wsgi import route
from ryu.app.wsgi import WSGIApplication
from ryu.lib import dpid as dpid_lib
simple_switch_instance_name = 'simple_switch_api_app'
url = '/simpleswitch/mactable/{dpid}'
class SimpleSwitchRest13(simple_switch_13.SimpleSwitch13):
_CONTEXTS = {'wsgi': WSGIApplication}
def __init__(self, *args, **kwargs):
super(SimpleSwitchRest13, self).__init__(*args, **kwargs)
self.switches = {}
wsgi = kwargs['wsgi']
wsgi.register(SimpleSwitchController,
{simple_switch_instance_name: self})
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
super(SimpleSwitchRest13, self).switch_features_handler(ev)
datapath = ev.msg.datapath
self.switches[datapath.id] = datapath
self.mac_to_port.setdefault(datapath.id, {})
def set_mac_to_port(self, dpid, entry):
mac_table = self.mac_to_port.setdefault(dpid, {})
datapath = self.switches.get(dpid)
entry_port = entry['port']
entry_mac = entry['mac']
if datapath is not None:
parser = datapath.ofproto_parser
if entry_port not in mac_table.values():
for mac, port in mac_table.items():
# from known device to new device
actions = [parser.OFPActionOutput(entry_port)]
match = parser.OFPMatch(in_port=port, eth_dst=entry_mac)
self.add_flow(datapath, 1, match, actions)
# from new device to known device
actions = [parser.OFPActionOutput(port)]
match = parser.OFPMatch(in_port=entry_port, eth_dst=mac)
self.add_flow(datapath, 1, match, actions)
mac_table.update({entry_mac: entry_port})
return mac_table
class SimpleSwitchController(ControllerBase):
def __init__(self, req, link, data, **config):
super(SimpleSwitchController, self).__init__(req, link, data, **config)
self.simple_switch_app = data[simple_switch_instance_name]
@route('simpleswitch', url, methods=['GET'],
requirements={'dpid': dpid_lib.DPID_PATTERN})
def list_mac_table(self, req, **kwargs):
simple_switch = self.simple_switch_app
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', 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 = kwargs['dpid']
try:
new_entry = req.json if req.body else {}
except ValueError:
raise Response(status=400)
if dpid not in simple_switch.mac_to_port:
return Response(status=404)
try:
mac_table = simple_switch.set_mac_to_port(dpid, new_entry)
body = json.dumps(mac_table)
return Response(content_type='application/json', text=body)
except Exception as e:
return Response(status=500)

View File

@ -1,121 +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.
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib import dpid as dpid_lib
from ryu.lib import stplib
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.app import simple_switch_13
class SimpleSwitch13(simple_switch_13.SimpleSwitch13):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
_CONTEXTS = {'stplib': stplib.Stp}
def __init__(self, *args, **kwargs):
super(SimpleSwitch13, self).__init__(*args, **kwargs)
self.mac_to_port = {}
self.stp = kwargs['stplib']
# Sample of stplib config.
# please refer to stplib.Stp.set_config() for details.
config = {dpid_lib.str_to_dpid('0000000000000001'):
{'bridge': {'priority': 0x8000}},
dpid_lib.str_to_dpid('0000000000000002'):
{'bridge': {'priority': 0x9000}},
dpid_lib.str_to_dpid('0000000000000003'):
{'bridge': {'priority': 0xa000}}}
self.stp.set_config(config)
def delete_flow(self, datapath):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
for dst in self.mac_to_port[datapath.id].keys():
match = parser.OFPMatch(eth_dst=dst)
mod = parser.OFPFlowMod(
datapath, command=ofproto.OFPFC_DELETE,
out_port=ofproto.OFPP_ANY, out_group=ofproto.OFPG_ANY,
priority=1, match=match)
datapath.send_msg(mod)
@set_ev_cls(stplib.EventPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
in_port = msg.match['in_port']
pkt = packet.Packet(msg.data)
eth = pkt.get_protocols(ethernet.ethernet)[0]
dst = eth.dst
src = eth.src
dpid = datapath.id
self.mac_to_port.setdefault(dpid, {})
self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
# learn a mac address to avoid FLOOD next time.
self.mac_to_port[dpid][src] = in_port
if dst in self.mac_to_port[dpid]:
out_port = self.mac_to_port[dpid][dst]
else:
out_port = ofproto.OFPP_FLOOD
actions = [parser.OFPActionOutput(out_port)]
# install a flow to avoid packet_in next time
if out_port != ofproto.OFPP_FLOOD:
match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
self.add_flow(datapath, 1, match, actions)
data = None
if msg.buffer_id == ofproto.OFP_NO_BUFFER:
data = msg.data
out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
in_port=in_port, actions=actions, data=data)
datapath.send_msg(out)
@set_ev_cls(stplib.EventTopologyChange, MAIN_DISPATCHER)
def _topology_change_handler(self, ev):
dp = ev.dp
dpid_str = dpid_lib.dpid_to_str(dp.id)
msg = 'Receive topology change event. Flush MAC table.'
self.logger.debug("[dpid=%s] %s", dpid_str, msg)
if dp.id in self.mac_to_port:
self.delete_flow(dp)
del self.mac_to_port[dp.id]
@set_ev_cls(stplib.EventPortStateChange, MAIN_DISPATCHER)
def _port_state_change_handler(self, ev):
dpid_str = dpid_lib.dpid_to_str(ev.dp.id)
of_state = {stplib.PORT_STATE_DISABLE: 'DISABLE',
stplib.PORT_STATE_BLOCK: 'BLOCK',
stplib.PORT_STATE_LISTEN: 'LISTEN',
stplib.PORT_STATE_LEARN: 'LEARN',
stplib.PORT_STATE_FORWARD: 'FORWARD'}
self.logger.debug("[dpid=%s][port=%d] state=%s",
dpid_str, ev.port_no, of_state[ev.port_state])

View File

@ -42,14 +42,15 @@ Get arp table:
15:0c:de:49": 2}}}
"""
import json
from webob import Response
from ryu.app import simple_switch_13
from ryu.app.wsgi import ControllerBase
from ryu.app.wsgi import rpc_public
from ryu.app.wsgi import websocket
from ryu.app.wsgi import WebSocketRPCServer
from ryu.app.wsgi import WSGIApplication
from ryu.app.wsgi import route, websocket, ControllerBase, WSGIApplication
from ryu.app.wsgi import rpc_public, WebSocketRPCServer
from ryu.controller import ofp_event
from ryu.controller.handler import set_ev_cls
from ryu.lib import hub
from ryu.lib.packet import packet

View File

@ -35,7 +35,7 @@ $ sudo mn --controller=remote --topo linear,2
""" # noqa
from socket import error as SocketError
from tinyrpc.exc import InvalidReplyError
from ryu.contrib.tinyrpc.exc import InvalidReplyError
from ryu.app.wsgi import (

View File

@ -17,34 +17,27 @@
import inspect
from types import MethodType
import webob.dec
from webob.response import Response
from ryu import cfg
from ryu.lib import hub
from routes import Mapper
from routes.util import URLGenerator
import six
import ryu.contrib
ryu.contrib.update_module_path()
from tinyrpc.server import RPCServer
from tinyrpc.dispatch import RPCDispatcher
from tinyrpc.dispatch import public as rpc_public
from tinyrpc.protocols.jsonrpc import JSONRPCProtocol
from tinyrpc.transports import ServerTransport, ClientTransport
from tinyrpc.client import RPCClient
import webob.dec
import webob.exc
from webob.request import Request as webob_Request
from webob.response import Response as webob_Response
from ryu import cfg
from ryu.lib import hub
DEFAULT_WSGI_HOST = '0.0.0.0'
DEFAULT_WSGI_PORT = 8080
ryu.contrib.restore_module_path()
CONF = cfg.CONF
CONF.register_cli_opts([
cfg.StrOpt(
'wsapi-host', default=DEFAULT_WSGI_HOST,
help='webapp listen host (default %s)' % DEFAULT_WSGI_HOST),
cfg.IntOpt(
'wsapi-port', default=DEFAULT_WSGI_PORT,
help='webapp listen port (default %s)' % DEFAULT_WSGI_PORT),
cfg.StrOpt('wsapi-host', default='', help='webapp listen host'),
cfg.IntOpt('wsapi-port', default=8080, help='webapp listen port')
])
HEX_PATTERN = r'0x[0-9a-z]+'
@ -63,33 +56,6 @@ def route(name, path, methods=None, requirements=None):
return _route
class Request(webob_Request):
"""
Wrapper class for webob.request.Request.
The behavior of this class is the same as webob.request.Request
except for setting "charset" to "UTF-8" automatically.
"""
DEFAULT_CHARSET = "UTF-8"
def __init__(self, environ, charset=DEFAULT_CHARSET, *args, **kwargs):
super(Request, self).__init__(
environ, charset=charset, *args, **kwargs)
class Response(webob_Response):
"""
Wrapper class for webob.response.Response.
The behavior of this class is the same as webob.response.Response
except for setting "charset" to "UTF-8" automatically.
"""
DEFAULT_CHARSET = "UTF-8"
def __init__(self, charset=DEFAULT_CHARSET, *args, **kwargs):
super(Response, self).__init__(charset=charset, *args, **kwargs)
class WebSocketRegistrationWrapper(object):
def __init__(self, func, controller):
@ -108,15 +74,8 @@ class WebSocketRegistrationWrapper(object):
class _AlreadyHandledResponse(Response):
# XXX: Eventlet API should not be used directly.
# 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
from eventlet.wsgi import ALREADY_HANDLED
_ALREADY_HANDLED = ALREADY_HANDLED
def __call__(self, environ, start_response):
return self._ALREADY_HANDLED
@ -124,7 +83,7 @@ class _AlreadyHandledResponse(Response):
def websocket(name, path):
def _websocket(controller_func):
def __websocket(self, req, **_):
def __websocket(self, req, **kwargs):
wrapper = WebSocketRegistrationWrapper(controller_func, self)
ws_wsgi = hub.WebSocketWSGI(wrapper)
ws_wsgi(req.environ, req.start_response)
@ -149,7 +108,6 @@ class ControllerBase(object):
def __init__(self, req, link, data, **config):
self.req = req
self.link = link
self.data = data
self.parent = None
for name, value in config.items():
setattr(self, name, value)
@ -180,10 +138,10 @@ class WebSocketServerTransport(ServerTransport):
if message is None:
raise WebSocketDisconnectedError()
context = None
return context, message
return (context, message)
def send_reply(self, context, reply):
self.ws.send(six.text_type(reply))
self.ws.send(unicode(reply))
class WebSocketRPCServer(RPCServer):
@ -213,7 +171,7 @@ class WebSocketClientTransport(ClientTransport):
self.queue = queue
def send_message(self, message, expect_reply=True):
self.ws.send(six.text_type(message))
self.ws.send(unicode(message))
if expect_reply:
return self.queue.get()
@ -266,15 +224,23 @@ class WSGIApplication(object):
self.registory = {}
self._wsmanager = WebSocketManager()
super(WSGIApplication, self).__init__()
# XXX: Switch how to call the API of Routes for every version
match_argspec = inspect.getargspec(self.mapper.match)
if 'environ' in match_argspec.args:
# New API
self._match = self._match_with_environ
else:
# Old API
self._match = self._match_with_path_info
def _match(self, req):
# Note: Invoke the new API, first. If the arguments unmatched,
# invoke the old API.
try:
return self.mapper.match(environ=req.environ)
except TypeError:
self.mapper.environ = req.environ
return self.mapper.match(req.path_info)
def _match_with_environ(self, req):
match = self.mapper.match(environ=req.environ)
return match
def _match_with_path_info(self, req):
self.mapper.environ = req.environ
match = self.mapper.match(req.path_info)
return match
@wsgify_hack
def __call__(self, req, start_response):

View File

@ -158,7 +158,6 @@ class RyuApp(object):
self.threads = []
self.main_thread = None
self.events = hub.Queue(128)
self._events_sem = hub.BoundedSemaphore(self.events.maxsize)
if hasattr(self.__class__, 'LOGGER_NAME'):
self.logger = logging.getLogger(self.__class__.LOGGER_NAME)
else:
@ -281,25 +280,13 @@ class RyuApp(object):
def _event_loop(self):
while self.is_active or not self.events.empty():
ev, state = self.events.get()
self._events_sem.release()
if ev == self._event_stop:
continue
handlers = self.get_handlers(ev, state)
for handler in handlers:
try:
handler(ev)
except hub.TaskExit:
# Normal exit.
# Propagate upwards, so we leave the event loop.
raise
except:
LOG.exception('%s: Exception occurred during handler processing. '
'Backtrace from offending handler '
'[%s] servicing event [%s] follows.',
self.name, handler.__name__, ev.__class__.__name__)
handler(ev)
def _send_event(self, ev, state):
self._events_sem.acquire()
self.events.put((ev, state))
def send_event(self, name, ev, state=None):
@ -349,7 +336,7 @@ class RyuApp(object):
class AppManager(object):
# singleton
# singletone
_instance = None
@staticmethod
@ -386,7 +373,6 @@ class AppManager(object):
self.applications = {}
self.contexts_cls = {}
self.contexts = {}
self.close_sem = hub.Semaphore()
def load_app(self, name):
mod = utils.import_module(name)
@ -534,7 +520,7 @@ class AppManager(object):
self._close(app)
events = app.events
if not events.empty():
app.logger.debug('%s events remains %d', app.name, events.qsize())
app.logger.debug('%s events remians %d', app.name, events.qsize())
def close(self):
def close_all(close_dict):
@ -542,10 +528,7 @@ class AppManager(object):
self._close(app)
close_dict.clear()
# This semaphore prevents parallel execution of this function,
# as run_apps's finally clause starts another close() call.
with self.close_sem:
for app_name in list(self.applications.keys()):
self.uninstantiate(app_name)
assert not self.applications
close_all(self.contexts)
for app_name in list(self.applications.keys()):
self.uninstantiate(app_name)
assert not self.applications
close_all(self.contexts)

View File

@ -36,7 +36,6 @@ CONF = oslo_config.cfg.ConfigOpts()
from oslo_config.cfg import ConfigOpts
from oslo_config.cfg import Opt
from oslo_config.cfg import BoolOpt
from oslo_config.cfg import IntOpt
from oslo_config.cfg import ListOpt

View File

@ -16,15 +16,22 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
from ryu.lib import hub
hub.patch(thread=False)
from ryu import cfg
# TODO:
# Right now, we have our own patched copy of ovs python bindings
# Once our modification is upstreamed and widely deployed,
# use it
#
# NOTE: this modifies sys.path and thus affects the following imports.
import ryu.contrib
ryu.contrib.update_module_path()
from ryu import cfg
import logging
import sys
from ryu import log
log.early_init_log(logging.DEBUG)
@ -46,28 +53,10 @@ CONF.register_cli_opts([
cfg.BoolOpt('enable-debugger', default=False,
help='don\'t overwrite Python standard threading library'
'(use only for debugging)'),
cfg.StrOpt('user-flags', default=None,
help='Additional flags file for user applications'),
])
def _parse_user_flags():
"""
Parses user-flags file and loads it to register user defined options.
"""
try:
idx = list(sys.argv).index('--user-flags')
user_flags_file = sys.argv[idx + 1]
except (ValueError, IndexError):
user_flags_file = ''
if user_flags_file and os.path.isfile(user_flags_file):
from ryu.utils import _import_module_file
_import_module_file(user_flags_file)
def main(args=None, prog=None):
_parse_user_flags()
try:
CONF(args=args, prog=prog,
project='ryu', version='ryu-manager %s' % version,
@ -77,20 +66,21 @@ def main(args=None, prog=None):
project='ryu', version='ryu-manager %s' % version)
log.init_log()
logger = logging.getLogger(__name__)
if CONF.enable_debugger:
LOG = logging.getLogger('ryu.cmd.manager')
msg = 'debugging is available (--enable-debugger option is turned on)'
logger.info(msg)
LOG.info(msg)
else:
hub.patch(thread=True)
if CONF.pid_file:
import os
with open(CONF.pid_file, 'w') as pid_file:
pid_file.write(str(os.getpid()))
app_lists = CONF.app_lists + CONF.app
# keep old behavior, run ofp if no application is specified.
# keep old behaivor, run ofp if no application is specified.
if not app_lists:
app_lists = ['ryu.controller.ofp_handler']
@ -107,9 +97,6 @@ def main(args=None, prog=None):
try:
hub.joinall(services)
except KeyboardInterrupt:
logger.debug("Keyboard Interrupt received. "
"Closing RYU application manager...")
finally:
app_mgr.close()

View File

@ -25,15 +25,18 @@
from __future__ import print_function
import cmd
import sys
import lxml.etree as ET
from ncclient.operations.rpc import RPCError
import ryu.contrib
ryu.contrib.update_module_path()
from ryu import cfg
import cmd
import sys
import lxml.etree as ET
from ryu.lib import of_config
from ryu.lib.of_config import capable_switch
from ncclient.operations.rpc import RPCError
import ryu.lib.of_config.classes as ofc

View File

@ -31,25 +31,24 @@
from __future__ import print_function
import ast
import ryu.contrib
ryu.contrib.update_module_path()
from ryu import cfg
import cmd
import signal
import socket
import sys
import termios
from ryu import cfg
from ryu.lib import rpc
CONF = cfg.CONF
CONF.register_cli_opts([
cfg.ListOpt('peers', default=[],
help='List of peers, separated by commas. '
'(e.g., "hoge=localhost:9998,fuga=localhost:9999")'),
cfg.StrOpt('command', short='c', default=None,
help='Command to be executed as single command. '
'The default is None and opens interactive console.'),
# eg. rpc-cli --peers=hoge=localhost:9998,fuga=localhost:9999
cfg.ListOpt('peers', default=[], help='list of peers')
])
@ -57,18 +56,16 @@ class Peer(object):
def __init__(self, name, addr):
self._name = name
self._addr = addr
self.socket = None
self.client = None
try:
self.connect()
except ConnectionError as e:
print('Exception when connecting to peer "%s": %s' % (name, e))
raise e
except:
pass
def connect(self):
self.socket = socket.create_connection(self._addr)
self.client = rpc.Client(self.socket,
notification_callback=self.notification)
self.client = None
s = socket.create_connection(self._addr)
self.client = rpc.Client(s, notification_callback=self.notification)
def try_to_connect(self, verbose=False):
if self.client:
@ -107,25 +104,12 @@ class Peer(object):
print("connected. retrying the request...")
return g()
def close(self):
self.socket.close()
peers = {}
def add_peer(name, host, port):
try:
peer = Peer(name, (host, port))
except ConnectionError:
return
peers[name] = peer
def close_peers():
for peer in peers.values():
peer.socket.close()
peers[name] = Peer(name, (host, port))
class Cmd(cmd.Cmd):
@ -140,9 +124,9 @@ class Cmd(cmd.Cmd):
try:
peer = args[0]
method = args[1]
params = ast.literal_eval(args[2])
except (IndexError, ValueError) as e:
print("argument error: %s" % e)
params = eval(args[2])
except:
print("argument error")
return
try:
p = peers[peer]
@ -190,8 +174,7 @@ class Cmd(cmd.Cmd):
def complete_notify(self, text, line, begidx, endidx):
return self._complete_peer(text, line, begidx, endidx)
def do_EOF(self, _line=None):
close_peers()
def do_EOF(self, _line):
sys.exit(0)
def emptyline(self):
@ -222,9 +205,6 @@ class Cmd(cmd.Cmd):
signal.signal(signal.SIGALRM, self._timeout)
signal.alarm(1)
def postloop(self):
close_peers()
def onecmd(self, string):
self._in_onecmd = True
try:
@ -253,11 +233,6 @@ def main(args=None, prog=None):
host, port = addr.rsplit(':', 1)
add_peer(name, host, port)
if CONF.command:
command = Cmd()
command.onecmd(CONF.command)
command.do_EOF()
Cmd().cmdloop()

View File

@ -14,13 +14,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import os.path
import sys
import ryu.contrib
ryu.contrib.update_module_path()
from ryu import cfg
from ryu import utils
from ryu import version
import argparse
import os.path
import sys
subcommands = {

View File

@ -1,9 +1,7 @@
import sys
_orig_sys_path = None
def update_module_path():
# Adjust module loading path for third party libraries
import os
@ -18,7 +16,6 @@ def update_module_path():
sys.path.remove(path)
sys.path.insert(0, path) # prioritize our own copy than system's
def restore_module_path():
global _orig_sys_path

View File

@ -1,4 +1,4 @@
# Copyright (C) 2017 Nippon Telegraph and Telephone Corporation.
# Copyright 2009 Shikhar Bhushan
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -8,13 +8,15 @@
#
# 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.
# 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.
"""
Client implementation for Zebra protocol service.
import sys
This module provides the client side implementation for Zebra protocol.
"""
if sys.version_info < (2, 6):
raise RuntimeError('You need Python 2.6+ for this module.')
class NCClientError(Exception):
"Base type for all NCClient errors"
pass

View File

@ -0,0 +1,68 @@
# Copyright 2009 Shikhar Bhushan
#
# 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.
def _abbreviate(uri):
if uri.startswith("urn:ietf:params") and ":netconf:" in uri:
splitted = uri.split(":")
if ":capability:" in uri:
if uri.startswith("urn:ietf:params:xml:ns:netconf"):
name, version = splitted[7], splitted[8]
else:
name, version = splitted[5], splitted[6]
return [ ":" + name, ":" + name + ":" + version ]
elif ":base:" in uri:
if uri.startswith("urn:ietf:params:xml:ns:netconf"):
return [ ":base", ":base" + ":" + splitted[7] ]
else:
return [ ":base", ":base" + ":" + splitted[5] ]
return []
def schemes(url_uri):
"Given a URI that has a *scheme* query string (i.e. `:url` capability URI), will return a list of supported schemes."
return url_uri.partition("?scheme=")[2].split(",")
class Capabilities:
"Represents the set of capabilities available to a NETCONF client or server. It is initialized with a list of capability URI's."
def __init__(self, capabilities):
self._dict = {}
for uri in capabilities:
self._dict[uri] = _abbreviate(uri)
def __contains__(self, key):
if key in self._dict:
return True
for abbrs in self._dict.values():
if key in abbrs:
return True
return False
def __len__(self):
return len(self._dict)
def __iter__(self):
return self._dict.iterkeys()
def __repr__(self):
return repr(self._dict.keys())
def add(self, uri):
"Add a capability."
self._dict[uri] = _abbreviate(uri)
def remove(self, uri):
"Remove a capability."
if key in self._dict:
del self._dict[key]

View File

@ -0,0 +1,24 @@
# Copyright 2009 Shikhar Bhushan
#
# 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.
from ncclient.transport import SessionListener
class PrintListener(SessionListener):
def callback(self, root, raw):
print('\n# RECEIVED MESSAGE with root=[tag=%r, attrs=%r] #\n%r\n' %
(root[0], root[1], raw))
def errback(self, err):
print('\n# RECEIVED ERROR #\n%r\n' % err)

View File

@ -0,0 +1,177 @@
# Copyright 2009 Shikhar Bhushan
# Copyright 2011 Leonidas Poulopoulos
#
# 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.
"""This module is a thin layer of abstraction around the library. It exposes all core functionality."""
import capabilities
import operations
import transport
import logging
logger = logging.getLogger('ncclient.manager')
CAPABILITIES = [
"urn:ietf:params:netconf:base:1.0",
"urn:ietf:params:netconf:capability:writable-running:1.0",
"urn:ietf:params:netconf:capability:candidate:1.0",
"urn:ietf:params:netconf:capability:confirmed-commit:1.0",
"urn:ietf:params:netconf:capability:rollback-on-error:1.0",
"urn:ietf:params:netconf:capability:startup:1.0",
"urn:ietf:params:netconf:capability:url:1.0?scheme=http,ftp,file,https,sftp",
"urn:ietf:params:netconf:capability:validate:1.0",
"urn:ietf:params:netconf:capability:xpath:1.0",
"urn:liberouter:params:netconf:capability:power-control:1.0",
"urn:ietf:params:netconf:capability:interleave:1.0"
]
"""A list of URI's representing the client's capabilities. This is used during the initial capability exchange. Modify this if you need to announce some capability not already included."""
OPERATIONS = {
"get": operations.Get,
"get_config": operations.GetConfig,
"dispatch": operations.Dispatch,
"edit_config": operations.EditConfig,
"copy_config": operations.CopyConfig,
"validate": operations.Validate,
"commit": operations.Commit,
"discard_changes": operations.DiscardChanges,
"delete_config": operations.DeleteConfig,
"lock": operations.Lock,
"unlock": operations.Unlock,
"close_session": operations.CloseSession,
"kill_session": operations.KillSession,
"poweroff_machine": operations.PoweroffMachine,
"reboot_machine": operations.RebootMachine
}
"""Dictionary of method names and corresponding :class:`~ncclient.operations.RPC` subclasses. It is used to lookup operations, e.g. `get_config` is mapped to :class:`~ncclient.operations.GetConfig`. It is thus possible to add additional operations to the :class:`Manager` API."""
def connect_ssh(*args, **kwds):
"""Initialize a :class:`Manager` over the SSH transport. For documentation of arguments see :meth:`ncclient.transport.SSHSession.connect`.
The underlying :class:`ncclient.transport.SSHSession` is created with :data:`CAPABILITIES`. It is first instructed to :meth:`~ncclient.transport.SSHSession.load_known_hosts` and then all the provided arguments are passed directly to its implementation of :meth:`~ncclient.transport.SSHSession.connect`.
"""
session = transport.SSHSession(capabilities.Capabilities(CAPABILITIES))
session.load_known_hosts()
session.connect(*args, **kwds)
return Manager(session)
connect = connect_ssh
"Same as :func:`connect_ssh`, since SSH is the default (and currently, the only) transport."
class OpExecutor(type):
def __new__(cls, name, bases, attrs):
def make_wrapper(op_cls):
def wrapper(self, *args, **kwds):
return self.execute(op_cls, *args, **kwds)
wrapper.func_doc = op_cls.request.func_doc
return wrapper
for op_name, op_cls in OPERATIONS.iteritems():
attrs[op_name] = make_wrapper(op_cls)
return super(OpExecutor, cls).__new__(cls, name, bases, attrs)
class Manager(object):
"""For details on the expected behavior of the operations and their parameters refer to :rfc:`4741`.
Manager instances are also context managers so you can use it like this::
with manager.connect("host") as m:
# do your stuff
... or like this::
m = manager.connect("host")
try:
# do your stuff
finally:
m.close_session()
"""
__metaclass__ = OpExecutor
def __init__(self, session, timeout=30):
self._session = session
self._async_mode = False
self._timeout = timeout
self._raise_mode = operations.RaiseMode.ALL
def __enter__(self):
return self
def __exit__(self, *args):
self.close_session()
return False
def __set_timeout(self, timeout):
self._timeout = timeout
def __set_async_mode(self, mode):
self._async_mode = mode
def __set_raise_mode(self, mode):
assert(mode in (operations.RaiseMode.NONE, operations.RaiseMode.ERRORS, operations.RaiseMode.ALL))
self._raise_mode = mode
def execute(self, cls, *args, **kwds):
return cls(self._session,
async=self._async_mode,
timeout=self._timeout,
raise_mode=self._raise_mode).request(*args, **kwds)
def locked(self, target):
"""Returns a context manager for a lock on a datastore, where *target* is the name of the configuration datastore to lock, e.g.::
with m.locked("running"):
# do your stuff
... instead of::
m.lock("running")
try:
# do your stuff
finally:
m.unlock("running")
"""
return operations.LockContext(self._session, target)
@property
def client_capabilities(self):
":class:`~ncclient.capabilities.Capabilities` object representing the client's capabilities."
return self._session._client_capabilities
@property
def server_capabilities(self):
":class:`~ncclient.capabilities.Capabilities` object representing the server's capabilities."
return self._session._server_capabilities
@property
def session_id(self):
"`session-id` assigned by the NETCONF server."
return self._session.id
@property
def connected(self):
"Whether currently connected to the NETCONF server."
return self._session.connected
async_mode = property(fget=lambda self: self._async_mode, fset=__set_async_mode)
"Specify whether operations are executed asynchronously (`True`) or synchronously (`False`) (the default)."
timeout = property(fget=lambda self: self._timeout, fset=__set_timeout)
"Specify the timeout for synchronous RPC requests."
raise_mode = property(fget=lambda self: self._raise_mode, fset=__set_raise_mode)
"Specify which errors are raised as :exc:`~ncclient.operations.RPCError` exceptions. Valid values are the constants defined in :class:`~ncclient.operations.RaiseMode`. The default value is :attr:`~ncclient.operations.RaiseMode.ALL`."

Some files were not shown because too many files have changed in this diff Show More