diff --git a/.github/workflows/tests-unit.yml b/.github/workflows/tests-unit.yml new file mode 100644 index 00000000..0395e44f --- /dev/null +++ b/.github/workflows/tests-unit.yml @@ -0,0 +1,25 @@ +name: Unit tests + +on: [push, pull_request] + +jobs: + unit-tests: + name: Unit tests + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.5, 3.6, 3.7, 3.8, 3.9] + steps: + - name: Checkout repo + uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox tox-gh-actions coveralls + bash ryu/tests/integrated/common/install_docker_test_pkg_for_github_actions.sh + - name: Test with tox + run: NOSE_VERBOSE=0 tox diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 00000000..b0d6d443 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,11 @@ +version: 2 +build: + image: latest +python: + version: 3.6 + install: + - method: pip + path: . +sphinx: + configuration: doc/source/conf.py +formats: all diff --git a/.renovaterc.json b/.renovaterc.json new file mode 100644 index 00000000..e1e004b7 --- /dev/null +++ b/.renovaterc.json @@ -0,0 +1,15 @@ +{ + "separateMajorMinor": false, + "schedule": [ + "after 10pm every weekday", + "before 5am every weekday", + "every weekend" + ], + "timezone": "Pacific/Auckland", + "extends": [ + "config:base", + ":prHourlyLimit1", + ":preserveSemverRanges", + "docker:enableMajor" + ] +} diff --git a/.stickler.yml b/.stickler.yml new file mode 100644 index 00000000..7fcbba89 --- /dev/null +++ b/.stickler.yml @@ -0,0 +1,9 @@ +--- +linters: + flake8: + python: 3 + max-line-length: 120 + pep8: + python: 3 + max-line-length: 120 + py3k: diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c6ef2609..00000000 --- a/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -language: python -python: - - "3.5" # Python 3.5 still needs to be installed on Travis-CI - -env: - - TOX_ENV=py27 - - TOX_ENV=py34 - - TOX_ENV=py35 - - TOX_ENV=pypy26 - - TOX_ENV=pycodestyle - - TOX_ENV=autopep8 - -services: - - docker - -sudo: required # Required to enable Docker service - -install: - - pip install tox coveralls - - bash ryu/tests/integrated/common/install_docker_test_pkg_for_travis.sh - -script: - - NOSE_VERBOSE=0 tox -e $TOX_ENV - -after_success: - - coveralls diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 11387509..c2ce5ca3 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -5,20 +5,8 @@ How to Get Your Change Into Ryu Submitting a change =================== -Send patches to ryu-devel@lists.sourceforge.net. Please don't use "Pull -Request" on GitHub. We expect you to send patches in "git-format-patch" -style. - -.. code-block:: bash - - # "N" means the number of commits to be included - $ git format-patch -s HEAD~N - - # To add cover (e.g., [PATCH 0/X]), specify "--cover-letter" option - $ git format-patch -s --cover-letter HEAD~N - - # You can send patches by "git send-email" command - $ git send-email --to="ryu-devel@lists.sourceforge.net" *.patch +To send patches to ryu, please make a +`pull request `_ on GitHub. Please check your changes with autopep8, pycodestyle(pep8) and running unit tests to make sure that they don't break the existing features. @@ -42,9 +30,9 @@ features (it's not a must though). Python version and libraries ============================ -* Python 2.7, 3.4, 3.5: +* Python 3.5, 3.6, 3.7, 3.8, 3.9: - Ryu supports multiple Python version. CI tests on Travis-CI is running + Ryu supports multiple Python versions. CI tests on GitHub Actions is running on these versions. * standard library + widely used library: diff --git a/README.rst b/README.rst index 1a54ae7c..33d02c84 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,7 @@ What's Ryu ========== Ryu is a component-based software defined networking framework. -Ryu provides software components with well defined API that make it +Ryu provides software components with well defined API's that make it easy for developers to create new network management and control applications. Ryu supports various protocols for managing network devices, such as OpenFlow, Netconf, OF-config, etc. About OpenFlow, @@ -20,7 +20,7 @@ Installing Ryu is quite easy:: If you prefer to install Ryu from the source code:: - % git clone git://github.com/osrg/ryu.git + % git clone https://github.com/faucetsdn/ryu.git % cd ryu; pip install . If you want to write your Ryu application, have a look at @@ -33,14 +33,14 @@ After writing your application, just type:: Optional Requirements ===================== -Some functionalities of ryu requires extra packages: +Some functions of ryu require extra packages: - OF-Config requires lxml and ncclient - NETCONF requires paramiko - BGP speaker (SSH console) requires paramiko - Zebra protocol service (database) requires SQLAlchemy -If you want to use the functionalities, please install requirements:: +If you want to use these functions, please install the requirements:: % pip install -r tools/optional-requires @@ -49,8 +49,8 @@ Please refer to tools/optional-requires for details. Prerequisites ============= -If you got some error messages at installation step, please confirm -dependencies for building required Python packages. +If you got some error messages at the installation stage, please confirm +dependencies for building the required Python packages. On Ubuntu(16.04 LTS or later):: @@ -59,7 +59,7 @@ On Ubuntu(16.04 LTS or later):: Support ======= -Ryu Official site is ``_. +Ryu Official site is ``_. If you have any questions, suggestions, and patches, the mailing list is available at diff --git a/debian/control b/debian/control index 8bcbe683..fd5af74a 100644 --- a/debian/control +++ b/debian/control @@ -6,7 +6,7 @@ Build-Depends: debhelper (>= 9.0.0), python-all (>= 2.6), python-sphinx Build-Depends-Indep: python-eventlet, python-lxml, - python-msgpack (>= 0.3.0), + python-msgpack (>= 0.4.0), python-netaddr, python-oslo.config (>= 1:1.2.0), python-paramiko, @@ -17,9 +17,9 @@ Build-Depends-Indep: python-pip, python-pbr Standards-Version: 3.9.5 -Homepage: http://osrg.github.io/ryu/ -Vcs-Git: git://github.com/osrg/ryu.git -Vcs-Browser: http://github.com/osrg/ryu +Homepage: https://ryu-sdn.org +Vcs-Git: git://github.com/faucetsdn/ryu.git +Vcs-Browser: https://github.com/faucetsdn/ryu XS-Python-Version: >= 2.6 Package: python-ryu @@ -28,7 +28,7 @@ Section: python Depends: python-eventlet, python-lxml, - python-msgpack (>= 0.3.0), + python-msgpack (>= 0.4.0), python-netaddr, python-oslo.config (>= 1:1.2.0), python-paramiko, diff --git a/debian/copyright b/debian/copyright index 63d77d3b..f05255cb 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,6 +1,6 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: ryu -Source: http://github.com/osrg/ryu +Source: http://github.com/faucetsdn/ryu Files: * Copyright: 2014 Ryu Project Team diff --git a/doc/source/app.rst b/doc/source/app.rst index 69376dba..eb8bbc20 100644 --- a/doc/source/app.rst +++ b/doc/source/app.rst @@ -12,3 +12,4 @@ Others provide some functionalities to other Ryu applications. app/ofctl.rst app/ofctl_rest.rst app/rest_vtep.rst + app/bgp_application.rst diff --git a/doc/source/app/bgp_application.rst b/doc/source/app/bgp_application.rst new file mode 100644 index 00000000..47e9fa89 --- /dev/null +++ b/doc/source/app/bgp_application.rst @@ -0,0 +1,6 @@ +************************************** +ryu.services.protocols.bgp.application +************************************** + +.. automodule:: ryu.services.protocols.bgp.application + :members: diff --git a/doc/source/library.rst b/doc/source/library.rst index ff280415..cdaed768 100644 --- a/doc/source/library.rst +++ b/doc/source/library.rst @@ -15,3 +15,4 @@ Ryu provides some useful library for your network applications. library_bgp_speaker_ref.rst library_mrt.rst library_ovsdb_manager.rst + library_ovsdb.rst diff --git a/doc/source/library_ovsdb.rst b/doc/source/library_ovsdb.rst new file mode 100644 index 00000000..df7d1708 --- /dev/null +++ b/doc/source/library_ovsdb.rst @@ -0,0 +1,76 @@ +************* +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=[]) + 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: diff --git a/doc/source/nicira_ext_ref.rst b/doc/source/nicira_ext_ref.rst index 739349c4..7ca1b0c7 100644 --- a/doc/source/nicira_ext_ref.rst +++ b/doc/source/nicira_ext_ref.rst @@ -54,6 +54,7 @@ The followings shows the supported NXAction classes in OpenFlow1.0 or later .. autoclass:: NXActionCT .. autoclass:: NXActionNAT .. autoclass:: NXActionOutputTrunc +.. autoclass:: NXActionDecNshTtl .. autoclass:: NXFlowSpecMatch .. autoclass:: NXFlowSpecLoad .. autoclass:: NXFlowSpecOutput diff --git a/doc/source/test-of-config-with-linc.rst b/doc/source/test-of-config-with-linc.rst index 2ff493e5..0f8c8fa4 100644 --- a/doc/source/test-of-config-with-linc.rst +++ b/doc/source/test-of-config-with-linc.rst @@ -19,7 +19,7 @@ The test procedure * run LINC switch * run Ryu test_of_config app -For getting/installing Ryu itself, please refer to http://osrg.github.io/ryu/ +For getting/installing Ryu itself, please refer to https://ryu-sdn.org/ Install Erlang environment diff --git a/doc/source/using_with_openstack.rst b/doc/source/using_with_openstack.rst index 5e153486..13bd9a1e 100644 --- a/doc/source/using_with_openstack.rst +++ b/doc/source/using_with_openstack.rst @@ -14,7 +14,7 @@ Using Ryu Network Operating System with OpenStack as OpenFlow controller Ryu cooperates with OpenStack using Quantum Ryu plugin. The plugin is available in the official Quantum releases. -For more information, please visit http://github.com/osrg/ryu/wiki/OpenStack . +For more information, please visit https://github.com/faucetsdn/ryu/wiki/OpenStack . We described instructions of the installation / configuration of OpenStack with Ryu, and we provide pre-configured VM image to be able to easily try OpenStack with Ryu. diff --git a/doc/source/writing_ryu_app.rst b/doc/source/writing_ryu_app.rst index ce68990b..a4d1830a 100644 --- a/doc/source/writing_ryu_app.rst +++ b/doc/source/writing_ryu_app.rst @@ -5,21 +5,21 @@ The First Application Whetting Your Appetite ====================== -If you want to manage the network gears (switches, routers, etc) at -your way, you need to write your Ryu application. Your application -tells Ryu how you want to manage the gears. Then Ryu configures the -gears by using OpenFlow protocol, etc. +If you want to manage network gear (switches, routers, etc) your +own way, you just need to write your own Ryu application. Your application +tells Ryu how you want to manage the gear. Then Ryu configures the +gear by using OpenFlow protocol, etc. -Writing Ryu application is easy. It's just Python scripts. +Writing Ryu applications is easy. They're just Python scripts. Start Writing ============= -We show a Ryu application that make OpenFlow switches work as a dumb +Here we show a Ryu application that makes an OpenFlow switch work as a dumb layer 2 switch. -Open a text editor creating a new file with the following content: +Open a text editor and create a new file with the following content: .. code-block:: python @@ -29,9 +29,9 @@ Open a text editor creating a new file with the following content: def __init__(self, *args, **kwargs): super(L2Switch, self).__init__(*args, **kwargs) -Ryu application is just a Python script so you can save the file with -any name, extensions, and any place you want. Let's name the file -'l2.py' at your home directory. +Ryu applications are just Python scripts so you can save the file with +any name, any extension, and any place you want. Let's name the file +'l2.py' in your home directory. This application does nothing useful yet, however it's a complete Ryu application. In fact, you can run this Ryu application:: @@ -44,7 +44,7 @@ application. In fact, you can run this Ryu application:: All you have to do is define a new subclass of RyuApp to run your Python script as a Ryu application. -Next let's add the functionality of sending a received packet to all +Next let's add some functionality that sends a received packet to all the ports. .. code-block:: python @@ -75,18 +75,18 @@ the ports. dp.send_msg(out) -A new method 'packet_in_handler' is added to L2Switch class. This is -called when Ryu receives an OpenFlow packet_in message. The trick is +A new method 'packet_in_handler' is added to the L2Switch class. This is +called when Ryu receives an OpenFlow packet_in message. The trick is the 'set_ev_cls' decorator. This decorator tells Ryu when the decorated function should be called. -The first argument of the decorator indicates an event that makes -function called. As you expect easily, every time Ryu gets a +The first argument of the decorator indicates which type of event this +function should be called for. As you might expect, every time Ryu gets a packet_in message, this function is called. -The second argument indicates the state of the switch. Probably, you +The second argument indicates the state of the switch. You probably want to ignore packet_in messages before the negotiation between Ryu -and the switch finishes. Using 'MAIN_DISPATCHER' as the second +and the switch is finished. Using 'MAIN_DISPATCHER' as the second argument means this function is called only after the negotiation completes. @@ -103,24 +103,24 @@ Ready for the second half. * OFPActionOutput class is used with a packet_out message to specify a switch port that you want to send the packet out of. This - application need a switch to send out of all the ports so OFPP_FLOOD - constant is used. + application uses the OFPP_FLOOD flag to indicate that the packet should + be sent out on all ports. * OFPPacketOut class is used to build a packet_out message. * If you call Datapath class's send_msg method with a OpenFlow message - class object, Ryu builds and send the on-wire data format to the switch. + class object, Ryu builds and sends the on-wire data format to the switch. -Here, you finished implementing your first Ryu application. You are ready to -run this Ryu application that does something useful. +There, you finished implementing your first Ryu application. You are ready to +run a Ryu application that does something useful. -A dumb l2 switch is too dumb? You want to implement a learning l2 +Is a dumb L2 switch is too dumb? You want to implement a learning L2 switch? Move to `the next step -`_. You +`_. You can learn from the existing Ryu applications at `ryu/app -`_ directory and +`_ directory and `integrated tests -`_ +`_ directory. diff --git a/ryu/__init__.py b/ryu/__init__.py index b3dccc8a..dae366a0 100644 --- a/ryu/__init__.py +++ b/ryu/__init__.py @@ -14,5 +14,5 @@ # limitations under the License. -version_info = (4, 21) +version_info = (4, 34) version = '.'.join(map(str, version_info)) diff --git a/ryu/app/gui_topology/gui_topology.py b/ryu/app/gui_topology/gui_topology.py index ed4857a5..cbac4d8f 100644 --- a/ryu/app/gui_topology/gui_topology.py +++ b/ryu/app/gui_topology/gui_topology.py @@ -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'] diff --git a/ryu/app/ofctl/api.py b/ryu/app/ofctl/api.py index 466b3314..1149e06d 100644 --- a/ryu/app/ofctl/api.py +++ b/ryu/app/ofctl/api.py @@ -16,22 +16,37 @@ # client for ryu.app.ofctl.service -import numbers - from ryu.base import app_manager from . import event -def get_datapath(app, dpid): +def get_datapath(app, dpid=None): """ Get datapath object by dpid. :param app: Client RyuApp instance - :param dpid: Datapath-id (in integer) + :param dpid: Datapath ID (int type) or None to get all datapath objects - Returns None on error. + 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) """ - assert isinstance(dpid, numbers.Integral) return app.send_request(event.GetDatapathRequest(dpid=dpid))() @@ -55,12 +70,19 @@ def send_msg(app, msg, reply_cls=None, reply_multi=False): Example:: - import ryu.app.ofctl.api as api + # ...(snip)... + import ryu.app.ofctl.api as ofctl_api - msg = parser.OFPPortDescStatsRequest(datapath=datapath) - result = api.send_msg(self, msg, - reply_cls=parser.OFPPortDescStatsReply, - reply_multi=True) + + 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) """ return app.send_request(event.SendMsgRequest(msg=msg, reply_cls=reply_cls, diff --git a/ryu/app/ofctl/event.py b/ryu/app/ofctl/event.py index 8919452e..dfb0024f 100644 --- a/ryu/app/ofctl/event.py +++ b/ryu/app/ofctl/event.py @@ -33,8 +33,8 @@ class _ReplyBase(event.EventReplyBase): # get datapath class GetDatapathRequest(_RequestBase): - def __init__(self, dpid): - assert isinstance(dpid, numbers.Integral) + def __init__(self, dpid=None): + assert dpid is None or isinstance(dpid, numbers.Integral) super(GetDatapathRequest, self).__init__() self.dpid = dpid diff --git a/ryu/app/ofctl/service.py b/ryu/app/ofctl/service.py index 2a2e97d1..eed51774 100644 --- a/ryu/app/ofctl/service.py +++ b/ryu/app/ofctl/service.py @@ -64,6 +64,22 @@ class OfctlService(app_manager.RyuApp): self.unobserve_event(ev_cls) self.logger.debug('ofctl: stop observing %s', ev_cls) + def _cancel(self, info, barrier_xid, exception): + xid = info.barriers.pop(barrier_xid) + req = info.xids.pop(xid) + msg = req.msg + datapath = msg.datapath + parser = datapath.ofproto_parser + is_barrier = isinstance(msg, parser.OFPBarrierRequest) + + info.results.pop(xid) + + if not is_barrier and req.reply_cls is not None: + self._unobserve_msg(req.reply_cls) + + self.logger.error('failed to send message <%s>', req.msg) + self.reply_to_request(req, event.Reply(exception=exception)) + @staticmethod def _is_error(msg): return (ofp_event.ofp_msg_to_ev_cls(type(msg)) == @@ -81,6 +97,9 @@ class OfctlService(app_manager.RyuApp): self._switches[id] = new_info if old_info: old_info.datapath.close() + for xid in list(old_info.barriers): + self._cancel( + old_info, xid, exception.InvalidDatapath(result=id)) @set_ev_cls(ofp_event.EventOFPStateChange, DEAD_DISPATCHER) def _handle_dead(self, ev): @@ -96,24 +115,25 @@ 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): - 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) + 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)) @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] @@ -132,7 +152,7 @@ class OfctlService(app_manager.RyuApp): si.xids[xid] = req si.barriers[barrier_xid] = xid - if isinstance(req.msg, parser.OFPBarrierRequest): + if is_barrier: barrier = msg datapath.set_xid(barrier) _store_xid(barrier.xid, barrier.xid) @@ -143,9 +163,15 @@ class OfctlService(app_manager.RyuApp): barrier = datapath.ofproto_parser.OFPBarrierRequest(datapath) datapath.set_xid(barrier) _store_xid(msg.xid, barrier.xid) - datapath.send_msg(msg) + if not datapath.send_msg(msg): + return self._cancel( + si, barrier.xid, + exception.InvalidDatapath(result=datapath.id)) - datapath.send_msg(barrier) + if not datapath.send_msg(barrier): + return self._cancel( + si, barrier.xid, + exception.InvalidDatapath(result=datapath.id)) @set_ev_cls(ofp_event.EventOFPBarrierReply, MAIN_DISPATCHER) def _handle_barrier(self, ev): diff --git a/ryu/app/rest_qos.py b/ryu/app/rest_qos.py index c5bac29a..ee3d45f4 100644 --- a/ryu/app/rest_qos.py +++ b/ryu/app/rest_qos.py @@ -1147,13 +1147,13 @@ class Action(object): if REST_ACTION in flow: actions = [] for act in flow[REST_ACTION]: - field_value = re.search('SET_FIELD: \{ip_dscp:(\d+)', act) + field_value = re.search(r'SET_FIELD: \{ip_dscp:(\d+)', act) if field_value: actions.append({REST_ACTION_MARK: field_value.group(1)}) - meter_value = re.search('METER:(\d+)', act) + meter_value = re.search(r'METER:(\d+)', act) if meter_value: actions.append({REST_ACTION_METER: meter_value.group(1)}) - queue_value = re.search('SET_QUEUE:(\d+)', act) + queue_value = re.search(r'SET_QUEUE:(\d+)', act) if queue_value: actions.append({REST_ACTION_QUEUE: queue_value.group(1)}) action = {REST_ACTION: actions} diff --git a/ryu/app/simple_switch_13.py b/ryu/app/simple_switch_13.py index 06a5d0ed..907425c9 100644 --- a/ryu/app/simple_switch_13.py +++ b/ryu/app/simple_switch_13.py @@ -85,7 +85,7 @@ class SimpleSwitch13(app_manager.RyuApp): dst = eth.dst src = eth.src - dpid = datapath.id + dpid = format(datapath.id, "d").zfill(16) self.mac_to_port.setdefault(dpid, {}) self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port) diff --git a/ryu/app/simple_switch_rest_13.py b/ryu/app/simple_switch_rest_13.py index aaf5d509..31f834f0 100644 --- a/ryu/app/simple_switch_rest_13.py +++ b/ryu/app/simple_switch_rest_13.py @@ -85,21 +85,21 @@ class SimpleSwitchController(ControllerBase): def list_mac_table(self, req, **kwargs): simple_switch = self.simple_switch_app - dpid = dpid_lib.str_to_dpid(kwargs['dpid']) + dpid = kwargs['dpid'] if dpid not in simple_switch.mac_to_port: return Response(status=404) mac_table = simple_switch.mac_to_port.get(dpid, {}) body = json.dumps(mac_table) - return Response(content_type='application/json', body=body) + return Response(content_type='application/json', text=body) @route('simpleswitch', url, methods=['PUT'], requirements={'dpid': dpid_lib.DPID_PATTERN}) def put_mac_table(self, req, **kwargs): simple_switch = self.simple_switch_app - dpid = dpid_lib.str_to_dpid(kwargs['dpid']) + dpid = kwargs['dpid'] try: new_entry = req.json if req.body else {} except ValueError: @@ -111,6 +111,6 @@ class SimpleSwitchController(ControllerBase): try: mac_table = simple_switch.set_mac_to_port(dpid, new_entry) body = json.dumps(mac_table) - return Response(content_type='application/json', body=body) + return Response(content_type='application/json', text=body) except Exception as e: return Response(status=500) diff --git a/ryu/controller/controller.py b/ryu/controller/controller.py index 84848917..698e375e 100644 --- a/ryu/controller/controller.py +++ b/ryu/controller/controller.py @@ -23,15 +23,17 @@ The main component of OpenFlow controller. """ import contextlib -from ryu import cfg import logging +import random +from socket import IPPROTO_TCP +from socket import TCP_NODELAY +from socket import SHUT_WR +from socket import timeout as SocketTimeout +import ssl + +from ryu import cfg from ryu.lib import hub from ryu.lib.hub import StreamServer -import random -import ssl -from socket import IPPROTO_TCP, TCP_NODELAY, SHUT_RDWR, timeout as SocketTimeout - -import netaddr import ryu.base.app_manager @@ -65,6 +67,7 @@ CONF.register_cli_opts([ cfg.StrOpt('ctl-privkey', default=None, help='controller private key'), cfg.StrOpt('ctl-cert', default=None, help='controller certificate'), cfg.StrOpt('ca-certs', default=None, help='CA certificates'), + cfg.StrOpt('ciphers', default=None, help='list of ciphers to enable'), cfg.ListOpt('ofp-switch-address-list', item_type=str, default=[], help='list of IP address and port pairs (default empty). ' 'e.g., "127.0.0.1:6653,[::1]:6653"'), @@ -163,6 +166,26 @@ class OpenFlowController(object): def server_loop(self, ofp_tcp_listen_port, ofp_ssl_listen_port): if CONF.ctl_privkey is not None and CONF.ctl_cert is not None: + if not hasattr(ssl, 'SSLContext'): + # anything less than python 2.7.9 supports only TLSv1 + # or less, thus we choose TLSv1 + ssl_args = {'ssl_version': ssl.PROTOCOL_TLSv1} + else: + # from 2.7.9 and versions 3.4+ ssl context creation is + # supported. Protocol_TLS from 2.7.13 and from 3.5.3 + # replaced SSLv23. Functionality is similar. + if hasattr(ssl, 'PROTOCOL_TLS'): + p = 'PROTOCOL_TLS' + else: + p = 'PROTOCOL_SSLv23' + + ssl_args = {'ssl_ctx': ssl.SSLContext(getattr(ssl, p))} + # Restrict non-safe versions + ssl_args['ssl_ctx'].options |= ssl.OP_NO_SSLv3 | ssl.OP_NO_SSLv2 + + if CONF.ciphers is not None: + ssl_args['ciphers'] = CONF.ciphers + if CONF.ca_certs is not None: server = StreamServer((CONF.ofp_listen_host, ofp_ssl_listen_port), @@ -170,15 +193,13 @@ class OpenFlowController(object): keyfile=CONF.ctl_privkey, certfile=CONF.ctl_cert, cert_reqs=ssl.CERT_REQUIRED, - ca_certs=CONF.ca_certs, - ssl_version=ssl.PROTOCOL_TLSv1) + ca_certs=CONF.ca_certs, **ssl_args) else: server = StreamServer((CONF.ofp_listen_host, ofp_ssl_listen_port), datapath_connection_factory, keyfile=CONF.ctl_privkey, - certfile=CONF.ctl_cert, - ssl_version=ssl.PROTOCOL_TLSv1) + certfile=CONF.ctl_cert, **ssl_args) else: server = StreamServer((CONF.ofp_listen_host, ofp_tcp_listen_port), @@ -194,12 +215,10 @@ def _deactivate(method): method(self) finally: try: - self.socket.shutdown(SHUT_RDWR) - except (EOFError, IOError): + self.socket.close() + except IOError: pass - if not self.is_active: - self.socket.close() return deactivate @@ -277,14 +296,24 @@ class Datapath(ofproto_protocol.ProtocolDesc): self._ports = None self.flow_format = ofproto_v1_0.NXFF_OPENFLOW10 self.ofp_brick = ryu.base.app_manager.lookup_service_brick('ofp_event') + self.state = None # for pylint self.set_state(HANDSHAKE_DISPATCHER) - @_deactivate + def _close_write(self): + # Note: Close only further sends in order to wait for the switch to + # disconnect this connection. + try: + self.socket.shutdown(SHUT_WR) + except (EOFError, IOError): + pass + def close(self): - if self.state != DEAD_DISPATCHER: - self.set_state(DEAD_DISPATCHER) + self.set_state(DEAD_DISPATCHER) + self._close_write() def set_state(self, state): + if self.state == state: + return self.state = state ev = ofp_event.EventOFPStateChange(self) ev.state = state @@ -300,7 +329,7 @@ class Datapath(ofproto_protocol.ProtocolDesc): while self.state != DEAD_DISPATCHER: try: read_len = min_read_len - if (remaining_read_len > min_read_len): + if remaining_read_len > min_read_len: read_len = remaining_read_len ret = self.socket.recv(read_len) except SocketTimeout: @@ -312,14 +341,14 @@ class Datapath(ofproto_protocol.ProtocolDesc): except (EOFError, IOError): break - if len(ret) == 0: + if not ret: break buf += ret buf_len = len(buf) while buf_len >= min_read_len: (version, msg_type, msg_len, xid) = ofproto_parser.header(buf) - if (msg_len < min_read_len): + if msg_len < min_read_len: # Someone isn't playing nicely; log it, and try something sane. LOG.debug("Message with invalid length %s received from switch at address %s", msg_len, self.address) @@ -335,7 +364,9 @@ class Datapath(ofproto_protocol.ProtocolDesc): ev = ofp_event.ofp_msg_to_ev(msg) self.ofp_brick.send_event_to_observers(ev, self.state) - dispatchers = lambda x: x.callers[ev.__class__].dispatchers + def dispatchers(x): + return x.callers[ev.__class__].dispatchers + handlers = [handler for handler in self.ofp_brick.get_handlers(ev) if self.state in dispatchers(handler)] @@ -358,9 +389,11 @@ class Datapath(ofproto_protocol.ProtocolDesc): def _send_loop(self): try: while self.state != DEAD_DISPATCHER: - buf = self.send_q.get() + buf, close_socket = self.send_q.get() self._send_q_sem.release() self.socket.sendall(buf) + if close_socket: + break except SocketTimeout: LOG.debug("Socket timed out while sending data to switch at address %s", self.address) @@ -380,14 +413,14 @@ class Datapath(ofproto_protocol.ProtocolDesc): self._send_q_sem.release() except hub.QueueEmpty: pass - # Finally, ensure the _recv_loop terminates. - self.close() + # Finally, disallow further sends. + self._close_write() - def send(self, buf): + def send(self, buf, close_socket=False): msg_enqueued = False self._send_q_sem.acquire() if self.send_q: - self.send_q.put(buf) + self.send_q.put((buf, close_socket)) msg_enqueued = True else: self._send_q_sem.release() @@ -402,13 +435,13 @@ class Datapath(ofproto_protocol.ProtocolDesc): msg.set_xid(self.xid) return self.xid - def send_msg(self, msg): + def send_msg(self, msg, close_socket=False): assert isinstance(msg, self.ofproto_parser.MsgBase) if msg.xid is None: self.set_xid(msg) msg.serialize() # LOG.debug('send_msg %s', msg) - return self.send(msg.buf) + return self.send(msg.buf, close_socket=close_socket) def _echo_request_loop(self): if not self.max_unreplied_echo_requests: @@ -424,7 +457,7 @@ class Datapath(ofproto_protocol.ProtocolDesc): def acknowledge_echo_reply(self, xid): try: self.unreplied_echo_requests.remove(xid) - except: + except ValueError: pass def serve(self): diff --git a/ryu/controller/dpset.py b/ryu/controller/dpset.py index 8004b2a8..45ead0e0 100644 --- a/ryu/controller/dpset.py +++ b/ryu/controller/dpset.py @@ -165,10 +165,33 @@ class DPSet(app_manager.RyuApp): """ DPSet application manages a set of switches (datapaths) connected to this controller. + + Usage Example:: + + # ...(snip)... + from ryu.controller import dpset + + + class MyApp(app_manager.RyuApp): + _CONTEXTS = { + 'dpset': dpset.DPSet, + } + + def __init__(self, *args, **kwargs): + super(MyApp, self).__init__(*args, **kwargs) + # Stores DPSet instance to call its API in this app + self.dpset = kwargs['dpset'] + + def _my_handler(self): + # Get the datapath object which has the given dpid + dpid = 1 + dp = self.dpset.get(dpid) + if dp is None: + self.logger.info('No such datapath: dpid=%d', dpid) """ def __init__(self, *args, **kwargs): - super(DPSet, self).__init__() + super(DPSet, self).__init__(*args, **kwargs) self.name = 'dpset' self.dps = {} # datapath_id => class Datapath @@ -238,9 +261,10 @@ class DPSet(app_manager.RyuApp): """ This method returns a list of tuples which represents instances for switches connected to this controller. - The tuple consists of a Datapath Id and an instance of + The tuple consists of a Datapath ID and an instance of ryu.controller.controller.Datapath. - A return value looks like the following: + + A return value looks like the following:: [ (dpid_A, Datapath_A), (dpid_B, Datapath_B), ... ] """ diff --git a/ryu/controller/ofp_handler.py b/ryu/controller/ofp_handler.py index 4f439c2e..5c4d46de 100644 --- a/ryu/controller/ofp_handler.py +++ b/ryu/controller/ofp_handler.py @@ -60,12 +60,13 @@ class OFPHandler(ryu.base.app_manager.RyuApp): return hub.spawn(self.controller) def _hello_failed(self, datapath, error_desc): - self.logger.error(error_desc) - error_msg = datapath.ofproto_parser.OFPErrorMsg(datapath) - error_msg.type = datapath.ofproto.OFPET_HELLO_FAILED - error_msg.code = datapath.ofproto.OFPHFC_INCOMPATIBLE - error_msg.data = error_desc - datapath.send_msg(error_msg) + self.logger.error('%s on datapath %s', error_desc, datapath.address) + error_msg = datapath.ofproto_parser.OFPErrorMsg( + datapath=datapath, + type_=datapath.ofproto.OFPET_HELLO_FAILED, + code=datapath.ofproto.OFPHFC_INCOMPATIBLE, + data=error_desc) + datapath.send_msg(error_msg, close_socket=True) @set_ev_handler(ofp_event.EventOFPHello, HANDSHAKE_DISPATCHER) def hello_handler(self, ev): diff --git a/ryu/lib/hub.py b/ryu/lib/hub.py index bd15fc89..cac989a5 100644 --- a/ryu/lib/hub.py +++ b/ryu/lib/hub.py @@ -42,6 +42,7 @@ if HUB_TYPE == 'eventlet': import ssl import socket import traceback + import sys getcurrent = eventlet.getcurrent patch = eventlet.monkey_patch @@ -126,11 +127,25 @@ if HUB_TYPE == 'eventlet': self.server = eventlet.listen(listen_info) if ssl_args: - def wrap_and_handle(sock, addr): - ssl_args.setdefault('server_side', True) - handle(ssl.wrap_socket(sock, **ssl_args), addr) + ssl_args.setdefault('server_side', True) + if 'ssl_ctx' in ssl_args: + ctx = ssl_args.pop('ssl_ctx') + ctx.load_cert_chain(ssl_args.pop('certfile'), + ssl_args.pop('keyfile')) + if 'cert_reqs' in ssl_args: + ctx.verify_mode = ssl_args.pop('cert_reqs') + if 'ca_certs' in ssl_args: + ctx.load_verify_locations(ssl_args.pop('ca_certs')) - self.handle = wrap_and_handle + def wrap_and_handle_ctx(sock, addr): + handle(ctx.wrap_socket(sock, **ssl_args), addr) + + self.handle = wrap_and_handle_ctx + else: + def wrap_and_handle_ssl(sock, addr): + handle(ssl.wrap_socket(sock, **ssl_args), addr) + + self.handle = wrap_and_handle_ssl else: self.handle = handle diff --git a/ryu/lib/ip.py b/ryu/lib/ip.py index c4094b9a..c75de162 100644 --- a/ryu/lib/ip.py +++ b/ryu/lib/ip.py @@ -84,7 +84,7 @@ def ipv4_to_str(ip): :param ip: binary or int type representation of IPv4 address :return: IPv4 address string """ - if isinstance(ip, int): + if isinstance(ip, numbers.Integral): return addrconv.ipv4.bin_to_text(struct.pack("!I", ip)) else: return addrconv.ipv4.bin_to_text(ip) diff --git a/ryu/lib/mrtlib.py b/ryu/lib/mrtlib.py index 83b4e536..c2d50c6e 100644 --- a/ryu/lib/mrtlib.py +++ b/ryu/lib/mrtlib.py @@ -264,6 +264,12 @@ class Ospf2MrtMessage(MrtMessage): # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ _HEADER_FMT = '!4s4s' HEADER_SIZE = struct.calcsize(_HEADER_FMT) + _TYPE = { + 'ascii': [ + 'remote_ip', + 'local_ip', + ], + } def __init__(self, remote_ip, local_ip, ospf_message): self.remote_ip = remote_ip @@ -328,6 +334,12 @@ class TableDumpMrtMessage(MrtMessage): # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ _HEADER_FMT = '' # should be defined in subclass HEADER_SIZE = 0 + _TYPE = { + 'ascii': [ + 'prefix', + 'peer_ip', + ], + } def __init__(self, view_num, seq_num, prefix, prefix_len, status, originated_time, peer_ip, peer_as, bgp_attributes, @@ -431,6 +443,11 @@ class TableDump2MrtRecord(MrtCommonRecord): SUBTYPE_RIB_IPV6_UNICAST = 4 SUBTYPE_RIB_IPV6_MULTICAST = 5 SUBTYPE_RIB_GENERIC = 6 + SUBTYPE_RIB_IPV4_UNICAST_ADDPATH = 8 + SUBTYPE_RIB_IPV4_MULTICAST_ADDPATH = 9 + SUBTYPE_RIB_IPV6_UNICAST_ADDPATH = 10 + SUBTYPE_RIB_IPV6_MULTICAST_ADDPATH = 11 + SUBTYPE_RIB_GENERIC_ADDPATH = 12 @TableDump2MrtMessage.register_type( @@ -452,6 +469,11 @@ class TableDump2PeerIndexTableMrtMessage(TableDump2MrtMessage): HEADER_SIZE = struct.calcsize(_HEADER_FMT) _PEER_COUNT_FMT = '!H' PEER_COUNT_SIZE = struct.calcsize(_PEER_COUNT_FMT) + _TYPE = { + 'ascii': [ + 'bgp_id', + ], + } def __init__(self, bgp_id, peer_entries, view_name='', view_name_len=None, peer_count=None): @@ -535,6 +557,13 @@ class MrtPeer(stringify.StringifyMixin): IP_ADDR_FAMILY_BIT = 1 << 0 AS_NUMBER_SIZE_BIT = 1 << 1 + _TYPE = { + 'ascii': [ + 'bgp_id', + 'ip_addr', + ], + } + def __init__(self, bgp_id, ip_addr, as_num, type_=0): self.type = type_ self.bgp_id = bgp_id @@ -595,7 +624,8 @@ class TableDump2AfiSafiSpecificRibMrtMessage(TableDump2MrtMessage): RIB subtypes. The AFI/SAFI-specific RIB subtypes consist of the RIB_IPV4_UNICAST, - RIB_IPV4_MULTICAST, RIB_IPV6_UNICAST, and RIB_IPV6_MULTICAST subtypes. + RIB_IPV4_MULTICAST, RIB_IPV6_UNICAST, RIB_IPV6_MULTICAST and their + additional-path version subtypes. """ # 0 1 2 3 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -614,6 +644,9 @@ class TableDump2AfiSafiSpecificRibMrtMessage(TableDump2MrtMessage): # Parser class to parse the Prefix field _PREFIX_CLS = None # should be defined in subclass + # Is additional-path version? + _IS_ADDPATH = False + def __init__(self, seq_num, prefix, rib_entries, entry_count=None): self.seq_num = seq_num assert isinstance(prefix, self._PREFIX_CLS) @@ -631,7 +664,7 @@ class TableDump2AfiSafiSpecificRibMrtMessage(TableDump2MrtMessage): rest = buf[2:] rib_entries = [] for i in range(entry_count): - r, rest = MrtRibEntry.parse(rest) + r, rest = MrtRibEntry.parse(rest, is_addpath=cls._IS_ADDPATH) rib_entries.insert(i, r) return entry_count, rib_entries, rest @@ -667,31 +700,104 @@ class TableDump2AfiSafiSpecificRibMrtMessage(TableDump2MrtMessage): @TableDump2MrtMessage.register_type( TableDump2MrtRecord.SUBTYPE_RIB_IPV4_UNICAST) -@TableDump2MrtMessage.register_type( - TableDump2MrtRecord.SUBTYPE_RIB_IPV4_MULTICAST) -class TableDump2RibIPv4UnicastMrtMessage(TableDump2AfiSafiSpecificRibMrtMessage): +class TableDump2RibIPv4UnicastMrtMessage( + TableDump2AfiSafiSpecificRibMrtMessage): """ MRT Message for the TABLE_DUMP_V2 Type and the - RIB_IPV4_UNICAST/SUBTYPE_RIB_IPV4_MULTICAST subtype. + SUBTYPE_RIB_IPV4_UNICAST subtype. + """ + _PREFIX_CLS = bgp.IPAddrPrefix + + +@TableDump2MrtMessage.register_type( + TableDump2MrtRecord.SUBTYPE_RIB_IPV4_MULTICAST) +class TableDump2RibIPv4MulticastMrtMessage( + TableDump2AfiSafiSpecificRibMrtMessage): + """ + MRT Message for the TABLE_DUMP_V2 Type and the + SUBTYPE_RIB_IPV4_MULTICAST subtype. """ _PREFIX_CLS = bgp.IPAddrPrefix @TableDump2MrtMessage.register_type( TableDump2MrtRecord.SUBTYPE_RIB_IPV6_UNICAST) -class TableDump2RibIPv6UnicastMrtMessage(TableDump2AfiSafiSpecificRibMrtMessage): +class TableDump2RibIPv6UnicastMrtMessage( + TableDump2AfiSafiSpecificRibMrtMessage): """ MRT Message for the TABLE_DUMP_V2 Type and the - RIB_IPV6_UNICAST/SUBTYPE_RIB_IPV6_MULTICAST subtype. + SUBTYPE_RIB_IPV6_MULTICAST subtype. """ _PREFIX_CLS = bgp.IP6AddrPrefix +@TableDump2MrtMessage.register_type( + TableDump2MrtRecord.SUBTYPE_RIB_IPV6_MULTICAST) +class TableDump2RibIPv6MulticastMrtMessage( + TableDump2AfiSafiSpecificRibMrtMessage): + """ + MRT Message for the TABLE_DUMP_V2 Type and the + SUBTYPE_RIB_IPV6_MULTICAST subtype. + """ + _PREFIX_CLS = bgp.IP6AddrPrefix + + +@TableDump2MrtMessage.register_type( + TableDump2MrtRecord.SUBTYPE_RIB_IPV4_UNICAST_ADDPATH) +class TableDump2RibIPv4UnicastAddPathMrtMessage( + TableDump2AfiSafiSpecificRibMrtMessage): + """ + MRT Message for the TABLE_DUMP_V2 Type and the + SUBTYPE_RIB_IPV4_UNICAST_ADDPATH subtype. + """ + _PREFIX_CLS = bgp.IPAddrPrefix + _IS_ADDPATH = True + + +@TableDump2MrtMessage.register_type( + TableDump2MrtRecord.SUBTYPE_RIB_IPV4_MULTICAST_ADDPATH) +class TableDump2RibIPv4MulticastAddPathMrtMessage( + TableDump2AfiSafiSpecificRibMrtMessage): + """ + MRT Message for the TABLE_DUMP_V2 Type and the + SUBTYPE_RIB_IPV4_MULTICAST_ADDPATH subtype. + """ + _PREFIX_CLS = bgp.IPAddrPrefix + _IS_ADDPATH = True + + +@TableDump2MrtMessage.register_type( + TableDump2MrtRecord.SUBTYPE_RIB_IPV6_UNICAST_ADDPATH) +class TableDump2RibIPv6UnicastAddPathMrtMessage( + TableDump2AfiSafiSpecificRibMrtMessage): + """ + MRT Message for the TABLE_DUMP_V2 Type and the + SUBTYPE_RIB_IPV6_UNICAST_ADDPATH subtype. + """ + _PREFIX_CLS = bgp.IP6AddrPrefix + _IS_ADDPATH = True + + +@TableDump2MrtMessage.register_type( + TableDump2MrtRecord.SUBTYPE_RIB_IPV6_MULTICAST_ADDPATH) +class TableDump2RibIPv6MulticastAddPathMrtMessage( + TableDump2AfiSafiSpecificRibMrtMessage): + """ + MRT Message for the TABLE_DUMP_V2 Type and the + SUBTYPE_RIB_IPV6_MULTICAST_ADDPATH subtype. + """ + _PREFIX_CLS = bgp.IP6AddrPrefix + _IS_ADDPATH = True + + @TableDump2MrtMessage.register_type( TableDump2MrtRecord.SUBTYPE_RIB_GENERIC) class TableDump2RibGenericMrtMessage(TableDump2MrtMessage): """ - MRT Message for the TABLE_DUMP_V2 Type and the RIB_GENERIC subtype. + MRT Message for the TABLE_DUMP_V2 Type and the generic RIB subtypes. + + The generic RIB subtypes consist of the RIB_GENERIC and + RIB_GENERIC_ADDPATH subtypes. """ # 0 1 2 3 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -707,6 +813,9 @@ class TableDump2RibGenericMrtMessage(TableDump2MrtMessage): _HEADER_FMT = '!IHB' HEADER_SIZE = struct.calcsize(_HEADER_FMT) + # Is additional-path version? + _IS_ADDPATH = False + def __init__(self, seq_num, afi, safi, nlri, rib_entries, entry_count=None): self.seq_num = seq_num @@ -727,7 +836,7 @@ class TableDump2RibGenericMrtMessage(TableDump2MrtMessage): rest = buf[2:] rib_entries = [] for i in range(entry_count): - r, rest = MrtRibEntry.parse(rest) + r, rest = MrtRibEntry.parse(rest, is_addpath=cls._IS_ADDPATH) rib_entries.insert(i, r) return entry_count, rib_entries, rest @@ -762,6 +871,16 @@ class TableDump2RibGenericMrtMessage(TableDump2MrtMessage): self.afi, self.safi) + nlri_bin + rib_bin +@TableDump2MrtMessage.register_type( + TableDump2MrtRecord.SUBTYPE_RIB_GENERIC_ADDPATH) +class TableDump2RibGenericAddPathMrtMessage(TableDump2RibGenericMrtMessage): + """ + MRT Message for the TABLE_DUMP_V2 Type and the RIB_GENERIC_ADDPATH + subtype. + """ + _IS_ADDPATH = True + + class MrtRibEntry(stringify.StringifyMixin): """ MRT RIB Entry. @@ -773,15 +892,21 @@ class MrtRibEntry(stringify.StringifyMixin): # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Originated Time | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # | (Path Identifier) | + # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Attribute Length | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | BGP Attributes... (variable) # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + # peer_index, originated_time, attr_len _HEADER_FMT = '!HIH' HEADER_SIZE = struct.calcsize(_HEADER_FMT) + # peer_index, originated_time, path_id, attr_len + _HEADER_FMT_ADDPATH = '!HIIH' + HEADER_SIZE_ADDPATH = struct.calcsize(_HEADER_FMT_ADDPATH) def __init__(self, peer_index, originated_time, bgp_attributes, - attr_len=None): + attr_len=None, path_id=None): self.peer_index = peer_index self.originated_time = originated_time assert isinstance(bgp_attributes, (list, tuple)) @@ -789,20 +914,28 @@ class MrtRibEntry(stringify.StringifyMixin): assert isinstance(attr, bgp._PathAttribute) self.bgp_attributes = bgp_attributes self.attr_len = attr_len + self.path_id = path_id @classmethod - def parse(cls, buf): - (peer_index, originated_time, attr_len) = struct.unpack_from( - cls._HEADER_FMT, buf) + def parse(cls, buf, is_addpath=False): + path_id = None + if not is_addpath: + (peer_index, originated_time, + attr_len) = struct.unpack_from(cls._HEADER_FMT, buf) + _header_size = cls.HEADER_SIZE + else: + (peer_index, originated_time, path_id, + attr_len) = struct.unpack_from(cls._HEADER_FMT_ADDPATH, buf) + _header_size = cls.HEADER_SIZE_ADDPATH - bgp_attr_bin = buf[cls.HEADER_SIZE:cls.HEADER_SIZE + attr_len] + bgp_attr_bin = buf[_header_size:_header_size + attr_len] bgp_attributes = [] while bgp_attr_bin: attr, bgp_attr_bin = bgp._PathAttribute.parser(bgp_attr_bin) bgp_attributes.append(attr) return cls(peer_index, originated_time, bgp_attributes, - attr_len), buf[cls.HEADER_SIZE + attr_len:] + attr_len, path_id), buf[_header_size + attr_len:] def serialize(self): bgp_attrs_bin = bytearray() @@ -810,10 +943,17 @@ class MrtRibEntry(stringify.StringifyMixin): bgp_attrs_bin += attr.serialize() self.attr_len = len(bgp_attrs_bin) # fixup - return struct.pack(self._HEADER_FMT, - self.peer_index, - self.originated_time, - self.attr_len) + bgp_attrs_bin + if self.path_id is None: + return struct.pack(self._HEADER_FMT, + self.peer_index, + self.originated_time, + self.attr_len) + bgp_attrs_bin + else: + return struct.pack(self._HEADER_FMT_ADDPATH, + self.peer_index, + self.originated_time, + self.path_id, + self.attr_len) + bgp_attrs_bin @six.add_metaclass(abc.ABCMeta) @@ -821,6 +961,12 @@ class Bgp4MpMrtMessage(MrtMessage): """ MRT Message for the BGP4MP Type. """ + _TYPE = { + 'ascii': [ + 'peer_ip', + 'local_ip', + ], + } @MrtRecord.register_type(MrtRecord.TYPE_BGP4MP) @@ -834,6 +980,10 @@ class Bgp4MpMrtRecord(MrtCommonRecord): SUBTYPE_BGP4MP_STATE_CHANGE_AS4 = 5 SUBTYPE_BGP4MP_MESSAGE_LOCAL = 6 SUBTYPE_BGP4MP_MESSAGE_AS4_LOCAL = 7 + SUBTYPE_BGP4MP_MESSAGE_ADDPATH = 8 + SUBTYPE_BGP4MP_MESSAGE_AS4_ADDPATH = 9 + SUBTYPE_BGP4MP_MESSAGE_LOCAL_ADDPATH = 10 + SUBTYPE_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH = 11 @MrtRecord.register_type(MrtRecord.TYPE_BGP4MP_ET) @@ -847,6 +997,10 @@ class Bgp4MpEtMrtRecord(ExtendedTimestampMrtRecord): SUBTYPE_BGP4MP_STATE_CHANGE_AS4 = 5 SUBTYPE_BGP4MP_MESSAGE_LOCAL = 6 SUBTYPE_BGP4MP_MESSAGE_AS4_LOCAL = 7 + SUBTYPE_BGP4MP_MESSAGE_ADDPATH = 8 + SUBTYPE_BGP4MP_MESSAGE_AS4_ADDPATH = 9 + SUBTYPE_BGP4MP_MESSAGE_LOCAL_ADDPATH = 10 + SUBTYPE_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH = 11 @Bgp4MpMrtMessage.register_type( diff --git a/ryu/lib/ofctl_string.py b/ryu/lib/ofctl_string.py index 06a91af2..fe0eeaea 100644 --- a/ryu/lib/ofctl_string.py +++ b/ryu/lib/ofctl_string.py @@ -39,7 +39,7 @@ def ofp_instruction_from_str(ofproto, action_str): action_str An action string. =========== ================================================= """ - action_re = re.compile("([a-z_]+)(\([^)]*\)|[^a-z_,()][^,()]*)*") + action_re = re.compile(r"([a-z_]+)(\([^)]*\)|[^a-z_,()][^,()]*)*") result = [] while len(action_str): m = action_re.match(action_str) @@ -303,7 +303,7 @@ class OfctlActionConverter(object): if k == 'table': recirc_table = str_to_int(v) elif k == 'zone': - m = re.search('\[(\d*)\.\.(\d*)\]', v) + m = re.search(r'\[(\d*)\.\.(\d*)\]', v) if m: zone_ofs_nbits = nicira_ext.ofs_nbits( int(m.group(1)), int(m.group(2))) @@ -322,3 +322,7 @@ class OfctlActionConverter(object): 'recirc_table': recirc_table, 'alg': alg, 'actions': ct_actions}) + + @classmethod + def ct_clear(cls, ofproto, action_str): + return dict(NXActionCTClear={}) diff --git a/ryu/lib/ovs/bridge.py b/ryu/lib/ovs/bridge.py index e48052fb..f86e9ae0 100644 --- a/ryu/lib/ovs/bridge.py +++ b/ryu/lib/ovs/bridge.py @@ -15,7 +15,7 @@ # limitations under the License. """ -slimmed down version of OVSBridge in quantum agent +Wrapper utility library of :py:mod:`ryu.lib.ovs.vsctl` """ import functools @@ -92,6 +92,26 @@ class TunnelPort(object): class OVSBridge(object): + """ + Class to provide wrapper utilities of :py:mod:`ryu.lib.ovs.vsctl.VSCtl` + + ``CONF`` is a instance of ``oslo_config.cfg.ConfigOpts``. + Mostly ``self.CONF`` is sufficient to instantiate this class from your Ryu + application. + + ``datapath_id`` specifies Datapath ID of the target OVS instance. + + ``ovsdb_addr`` specifies the address of the OVS instance. + Automatically validated when you call ``init()`` method. + Refer to :py:mod:`ryu.lib.ovs.vsctl.valid_ovsdb_addr` for the format of + this address. + + if ``timeout`` is omitted, ``CONF.ovsdb_timeout`` will be used as the + default value. + + Usage of ``timeout`` and ``exception`` is the same with ``timeout_sec`` + and ``exception`` of :py:mod:`ryu.lib.ovs.vsctl.VSCtl.run_command`. + """ def __init__(self, CONF, datapath_id, ovsdb_addr, timeout=None, exception=None): @@ -105,9 +125,25 @@ class OVSBridge(object): self.br_name = None def run_command(self, commands): + """ + Executes the given commands and sends OVSDB messages. + + ``commands`` must be a list of + :py:mod:`ryu.lib.ovs.vsctl.VSCtlCommand`. + + The given ``timeout`` and ``exception`` when instantiation will be used + to call :py:mod:`ryu.lib.ovs.vsctl.VSCtl.run_command`. + """ self.vsctl.run_command(commands, self.timeout, self.exception) def init(self): + """ + Validates the given ``ovsdb_addr`` and connects to OVS instance. + + If failed to connect to OVS instance or the given ``datapath_id`` does + not match with the Datapath ID of the connected OVS instance, raises + :py:mod:`ryu.lib.ovs.bridge.OVSBridgeNotFound` exception. + """ if not valid_ovsdb_addr(self.ovsdb_addr): raise ValueError('Invalid OVSDB address: %s' % self.ovsdb_addr) if self.br_name is None: @@ -126,16 +162,38 @@ class OVSBridge(object): return command.result[0].name def get_controller(self): + """ + Gets the configured OpenFlow controller address. + + This method is corresponding to the following ovs-vsctl command:: + + $ ovs-vsctl get-controller + """ command = ovs_vsctl.VSCtlCommand('get-controller', [self.br_name]) self.run_command([command]) - return command.result[0] + result = command.result + return result[0] if len(result) == 1 else result def set_controller(self, controllers): + """ + Sets the OpenFlow controller address. + + This method is corresponding to the following ovs-vsctl command:: + + $ ovs-vsctl set-controller ... + """ command = ovs_vsctl.VSCtlCommand('set-controller', [self.br_name]) command.args.extend(controllers) self.run_command([command]) def del_controller(self): + """ + Deletes the configured OpenFlow controller address. + + This method is corresponding to the following ovs-vsctl command:: + + $ ovs-vsctl del-controller + """ command = ovs_vsctl.VSCtlCommand('del-controller', [self.br_name]) self.run_command([command]) @@ -245,30 +303,72 @@ class OVSBridge(object): self.run_command([command]) def db_get_val(self, table, record, column): + """ + Gets values of 'column' in 'record' in 'table'. + + This method is corresponding to the following ovs-vsctl command:: + + $ ovs-vsctl get TBL REC COL + """ command = ovs_vsctl.VSCtlCommand('get', (table, record, column)) self.run_command([command]) assert len(command.result) == 1 return command.result[0] def db_get_map(self, table, record, column): + """ + Gets dict type value of 'column' in 'record' in 'table'. + + This method is corresponding to the following ovs-vsctl command:: + + $ ovs-vsctl get TBL REC COL + """ val = self.db_get_val(table, record, column) assert isinstance(val, dict) return val def get_datapath_id(self): + """ + Gets Datapath ID of OVS instance. + + This method is corresponding to the following ovs-vsctl command:: + + $ ovs-vsctl get Bridge datapath_id + """ return self.db_get_val('Bridge', self.br_name, 'datapath_id') def delete_port(self, port_name): + """ + Deletes a port on the OVS instance. + + This method is corresponding to the following ovs-vsctl command:: + + $ ovs-vsctl --if-exists del-port + """ command = ovs_vsctl.VSCtlCommand( 'del-port', (self.br_name, port_name), '--if-exists') self.run_command([command]) def get_ofport(self, port_name): + """ + Gets the OpenFlow port number. + + This method is corresponding to the following ovs-vsctl command:: + + $ ovs-vsctl get Interface ofport + """ ofport_list = self.db_get_val('Interface', port_name, 'ofport') assert len(ofport_list) == 1 return int(ofport_list[0]) def get_port_name_list(self): + """ + Gets a list of all ports on OVS instance. + + This method is corresponding to the following ovs-vsctl command:: + + $ ovs-vsctl list-ports + """ command = ovs_vsctl.VSCtlCommand('list-ports', (self.br_name, )) self.run_command([command]) return command.result @@ -297,6 +397,16 @@ class OVSBridge(object): def add_tunnel_port(self, name, tunnel_type, remote_ip, local_ip=None, key=None, ofport=None): + """ + Creates a tunnel port. + + :param name: Port name to be created + :param tunnel_type: Type of tunnel (gre or vxlan) + :param remote_ip: Remote IP address of tunnel + :param local_ip: Local IP address of tunnel + :param key: Key of GRE or VNI of VxLAN + :param ofport: Requested OpenFlow port number + """ options = 'remote_ip=%(remote_ip)s' % locals() if key: options += ',key=%(key)s' % locals() @@ -314,15 +424,32 @@ class OVSBridge(object): def add_gre_port(self, name, remote_ip, local_ip=None, key=None, ofport=None): + """ + Creates a GRE tunnel port. + + See the description of ``add_tunnel_port()``. + """ self.add_tunnel_port(name, 'gre', remote_ip, local_ip=local_ip, key=key, ofport=ofport) def add_vxlan_port(self, name, remote_ip, local_ip=None, key=None, ofport=None): + """ + Creates a VxLAN tunnel port. + + See the description of ``add_tunnel_port()``. + """ self.add_tunnel_port(name, 'vxlan', remote_ip, local_ip=local_ip, key=key, ofport=ofport) def del_port(self, port_name): + """ + Deletes a port on OVS instance. + + This method is corresponding to the following ovs-vsctl command:: + + $ ovs-vsctl del-port + """ command = ovs_vsctl.VSCtlCommand('del-port', (self.br_name, port_name)) self.run_command([command]) @@ -396,6 +523,9 @@ class OVSBridge(object): return None def set_qos(self, port_name, type='linux-htb', max_rate=None, queues=None): + """ + Sets a Qos rule and creates Queues on the given port. + """ queues = queues if queues else [] command_qos = ovs_vsctl.VSCtlCommand( 'set-qos', @@ -409,6 +539,9 @@ class OVSBridge(object): return None def del_qos(self, port_name): + """ + Deletes the Qos rule on the given port. + """ command = ovs_vsctl.VSCtlCommand( 'del-qos', [port_name]) diff --git a/ryu/lib/ovs/vsctl.py b/ryu/lib/ovs/vsctl.py index 2391c903..53ee7f42 100644 --- a/ryu/lib/ovs/vsctl.py +++ b/ryu/lib/ovs/vsctl.py @@ -14,6 +14,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +""" +``ovs-vsctl`` command like library to speak OVSDB protocol +""" from __future__ import print_function @@ -53,9 +56,9 @@ def valid_ovsdb_addr(addr): The valid formats are: - - unix:file - - tcp:ip:port - - ssl:ip:port + - ``unix:file`` + - ``tcp:ip:port`` + - ``ssl:ip:port`` If ip is IPv6 address, wrap ip with brackets (e.g., ssl:[::1]:6640). @@ -63,12 +66,12 @@ def valid_ovsdb_addr(addr): :return: True if valid, otherwise False. """ # Assumes Unix socket format: "unix:file" - m = re.match('unix:(\S+)', addr) + m = re.match(r'unix:(\S+)', addr) if m: file = m.group(1) return os.path.isfile(file) # Assumes TCP/SSL socket format: "tcp:ip:port" or "ssl:ip:port" - m = re.match('(tcp|ssl):(\S+):(\d+)', addr) + m = re.match(r'(tcp|ssl):(\S+):(\d+)', addr) if m: address = m.group(2) port = m.group(3) @@ -959,6 +962,34 @@ class _VSCtlTable(object): class VSCtlCommand(StringifyMixin): + """ + Class to describe artgumens similar to those of ``ovs-vsctl`` command. + + ``command`` specifies the command of ``ovs-vsctl``. + + ``args`` specifies a list or tuple of arguments for the given command. + + ``options`` specifies a list or tuple of options for the given command. + Please note that NOT all options of ``ovs-vsctl`` are supported. + For example, ``--id`` option is not yet supported. + This class supports the followings. + + ================= ========================================================= + Option Description + ================= ========================================================= + ``--may-exist`` Does nothing when the given port already exists. + The supported commands are ``add-port`` and + ``add-bond``. + ``--fake-iface`` Creates a port as a fake interface. + The supported command is ``add-bond``. + ``--must-exist`` Raises exception if the given port does not exist. + The supported command is ``del-port``. + ``--with-iface`` Takes effect to the interface which has the same name. + The supported command is ``del-port``. + ``--if-exists`` Ignores exception when not found. + The supported command is ``get``. + ================= ========================================================= + """ def __init__(self, command, args=None, options=None): super(VSCtlCommand, self).__init__() @@ -978,6 +1009,13 @@ class VSCtlCommand(StringifyMixin): class VSCtl(object): + """ + A class to describe an Open vSwitch instance. + + ``remote`` specifies the address of the OVS instance. + :py:mod:`ryu.lib.ovs.vsctl.valid_ovsdb_addr` is a convenient function to + validate this address. + """ def _reset(self): self.schema_helper = None @@ -1237,6 +1275,19 @@ class VSCtl(object): self._do_main(commands) def run_command(self, commands, timeout_sec=None, exception=None): + """ + Executes the given commands and sends OVSDB messages. + + ``commands`` must be a list of + :py:mod:`ryu.lib.ovs.vsctl.VSCtlCommand`. + + If ``timeout_sec`` is specified, raises exception after the given + timeout [sec]. Additionally, if ``exception`` is specified, this + function will wraps exception using the given exception class. + + Retruns ``None`` but fills ``result`` attribute for each command + instance. + """ if timeout_sec is None: self._run_command(commands) else: @@ -1563,7 +1614,9 @@ class VSCtl(object): self._pre_add_port(ctx, columns) def _cmd_add_port(self, ctx, command): - may_exist = command.has_option('--may_exist') + # '--may_exist' is a typo but for backword compatibility + may_exist = (command.has_option('--may_exist') + or command.has_option('--may-exist')) br_name = command.args[0] port_name = command.args[1] @@ -1577,7 +1630,9 @@ class VSCtl(object): False, iface_names, settings) def _cmd_add_bond(self, ctx, command): - may_exist = command.has_option('--may_exist') + # '--may_exist' is a typo but for backword compatibility + may_exist = (command.has_option('--may_exist') + or command.has_option('--may-exist')) fake_iface = command.has_option('--fake-iface') br_name = command.args[0] diff --git a/ryu/lib/packet/bgp.py b/ryu/lib/packet/bgp.py index 9e501515..89ed191e 100644 --- a/ryu/lib/packet/bgp.py +++ b/ryu/lib/packet/bgp.py @@ -782,7 +782,16 @@ class _LabelledAddrPrefix(_AddrPrefix): # Routes field should be set to 0x800000. (Of course, terminating the # BGP session also withdraws all the previously advertised routes.) # - _WITHDRAW_LABEL = 0x800000 + # RFC8227 + # 2.4 How to Explicitly Withdraw the Binding of a Label to a Prefix + # [RFC3107] also made it possible to withdraw a binding without specifying + # the label explicitly, by setting the Compatibility field to 0x800000. + # However, some implementations set it to 0x000000. In order to ensure + # backwards compatibility, it is RECOMMENDED by this document that the + # Compatibility field be set to 0x800000, but it is REQUIRED that it be + # ignored upon reception. + # + _WITHDRAW_LABELS = [0x800000, 0x000000] def __init__(self, length, addr, labels=None, **kwargs): labels = labels if labels else [] @@ -823,7 +832,7 @@ class _LabelledAddrPrefix(_AddrPrefix): labels = addr[0] rest = addr[1:] labels = [x << 4 for x in labels] - if labels and labels[-1] != cls._WITHDRAW_LABEL: + if labels and labels[-1] not in cls._WITHDRAW_LABELS: labels[-1] |= 1 # bottom of stack bin_labels = list(cls._label_to_bin(l) for l in labels) return bytes(reduce(lambda x, y: x + y, bin_labels, @@ -837,7 +846,7 @@ class _LabelledAddrPrefix(_AddrPrefix): while True: (label, bin_) = cls._label_from_bin(bin_) labels.append(label) - if label & 1 or label == cls._WITHDRAW_LABEL: + if label & 1 or label in cls._WITHDRAW_LABELS: break assert length > struct.calcsize(cls._LABEL_PACK_STR) * len(labels) except struct.error: @@ -857,7 +866,7 @@ class _LabelledAddrPrefix(_AddrPrefix): while True: (label, rest) = cls._label_from_bin(rest) labels.append(label >> 4) - if label & 1 or label == cls._WITHDRAW_LABEL: + if label & 1 or label in cls._WITHDRAW_LABELS: break return (labels,) + cls._prefix_from_bin(rest) diff --git a/ryu/lib/packet/bmp.py b/ryu/lib/packet/bmp.py index bc49c577..1320dd2e 100644 --- a/ryu/lib/packet/bmp.py +++ b/ryu/lib/packet/bmp.py @@ -60,6 +60,8 @@ BMP_STAT_TYPE_INV_UPDATE_DUE_TO_ORIGINATOR_ID = 5 BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_CONFED_LOOP = 6 BMP_STAT_TYPE_ADJ_RIB_IN = 7 BMP_STAT_TYPE_LOC_RIB = 8 +BMP_STAT_TYPE_ADJ_RIB_OUT = 14 +BMP_STAT_TYPE_EXPORT_RIB = 15 BMP_PEER_DOWN_REASON_UNKNOWN = 0 BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION = 1 @@ -69,7 +71,7 @@ BMP_PEER_DOWN_REASON_REMOTE_NO_NOTIFICATION = 4 class BMPMessage(packet_base.PacketBase, TypeDisp): - """Base class for BGP Monitoring Protocol messages. + r"""Base class for BGP Monitoring Protocol messages. An instance has the following attributes at least. Most of them are same to the on-wire counterparts but in host byte @@ -141,7 +143,7 @@ class BMPMessage(packet_base.PacketBase, TypeDisp): class BMPPeerMessage(BMPMessage): - """BMP Message with Per Peer Header + r"""BMP Message with Per Peer Header Following BMP Messages contain Per Peer Header after Common BMP Header. @@ -157,7 +159,8 @@ class BMPPeerMessage(BMPMessage): type Type field. one of BMP\_MSG\_ constants. peer_type The type of the peer. is_post_policy Indicate the message reflects the post-policy - Adj-RIB-In + is_adj_rib_out Indicate the message reflects Adj-RIB-Out (defaults + to Adj-RIB-In) peer_distinguisher Use for L3VPN router which can have multiple instance. peer_address The remote IP address associated with the TCP @@ -179,12 +182,13 @@ class BMPPeerMessage(BMPMessage): def __init__(self, peer_type, is_post_policy, peer_distinguisher, peer_address, peer_as, peer_bgp_id, timestamp, - version=VERSION, type_=None, len_=None): + version=VERSION, type_=None, len_=None, is_adj_rib_out=False): super(BMPPeerMessage, self).__init__(version=version, len_=len_, type_=type_) self.peer_type = peer_type self.is_post_policy = is_post_policy + self.is_adj_rib_out = is_adj_rib_out self.peer_distinguisher = peer_distinguisher self.peer_address = peer_address self.peer_as = peer_as @@ -200,6 +204,11 @@ class BMPPeerMessage(BMPMessage): rest = buf[struct.calcsize(cls._PEER_HDR_PACK_STR):] + if peer_flags & (1 << 4): + is_adj_rib_out = True + else: + is_adj_rib_out = False + if peer_flags & (1 << 6): is_post_policy = True else: @@ -221,12 +230,16 @@ class BMPPeerMessage(BMPMessage): "peer_address": peer_address, "peer_as": peer_as, "peer_bgp_id": peer_bgp_id, - "timestamp": timestamp + "timestamp": timestamp, + "is_adj_rib_out": is_adj_rib_out, }, rest def serialize_tail(self): flags = 0 + if self.is_adj_rib_out: + flags |= (1 << 4) + if self.is_post_policy: flags |= (1 << 6) @@ -250,7 +263,7 @@ class BMPPeerMessage(BMPMessage): @BMPMessage.register_type(BMP_MSG_ROUTE_MONITORING) class BMPRouteMonitoring(BMPPeerMessage): - """BMP Route Monitoring Message + r"""BMP Route Monitoring Message ========================== =============================================== Attribute Description @@ -275,7 +288,7 @@ class BMPRouteMonitoring(BMPPeerMessage): def __init__(self, bgp_update, peer_type, is_post_policy, peer_distinguisher, peer_address, peer_as, peer_bgp_id, timestamp, version=VERSION, type_=BMP_MSG_ROUTE_MONITORING, - len_=None): + len_=None, is_adj_rib_out=False): super(BMPRouteMonitoring, self).__init__(peer_type=peer_type, is_post_policy=is_post_policy, @@ -286,7 +299,8 @@ class BMPRouteMonitoring(BMPPeerMessage): timestamp=timestamp, len_=len_, type_=type_, - version=version) + version=version, + is_adj_rib_out=is_adj_rib_out) self.bgp_update = bgp_update @classmethod @@ -308,7 +322,7 @@ class BMPRouteMonitoring(BMPPeerMessage): @BMPMessage.register_type(BMP_MSG_STATISTICS_REPORT) class BMPStatisticsReport(BMPPeerMessage): - """BMP Statistics Report Message + r"""BMP Statistics Report Message ========================== =============================================== Attribute Description @@ -335,7 +349,8 @@ class BMPStatisticsReport(BMPPeerMessage): def __init__(self, stats, peer_type, is_post_policy, peer_distinguisher, peer_address, peer_as, peer_bgp_id, timestamp, - version=VERSION, type_=BMP_MSG_STATISTICS_REPORT, len_=None): + version=VERSION, type_=BMP_MSG_STATISTICS_REPORT, len_=None, + is_adj_rib_out=False): super(BMPStatisticsReport, self).__init__(peer_type=peer_type, is_post_policy=is_post_policy, @@ -346,7 +361,8 @@ class BMPStatisticsReport(BMPPeerMessage): timestamp=timestamp, len_=len_, type_=type_, - version=version) + version=version, + is_adj_rib_out=is_adj_rib_out) self.stats = stats @classmethod @@ -381,7 +397,9 @@ class BMPStatisticsReport(BMPPeerMessage): type_ == BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_CONFED_LOOP: value, = struct.unpack_from('!I', six.binary_type(value)) elif type_ == BMP_STAT_TYPE_ADJ_RIB_IN or \ - type_ == BMP_STAT_TYPE_LOC_RIB: + type_ == BMP_STAT_TYPE_LOC_RIB or \ + type_ == BMP_STAT_TYPE_ADJ_RIB_OUT or \ + type_ == BMP_STAT_TYPE_EXPORT_RIB: value, = struct.unpack_from('!Q', six.binary_type(value)) buf = buf[cls._MIN_LEN + len_:] @@ -410,7 +428,9 @@ class BMPStatisticsReport(BMPPeerMessage): t == BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_CONFED_LOOP: valuepackstr = 'I' elif t == BMP_STAT_TYPE_ADJ_RIB_IN or \ - t == BMP_STAT_TYPE_LOC_RIB: + t == BMP_STAT_TYPE_LOC_RIB or \ + t == BMP_STAT_TYPE_ADJ_RIB_OUT or \ + t == BMP_STAT_TYPE_EXPORT_RIB: valuepackstr = 'Q' else: continue @@ -424,7 +444,7 @@ class BMPStatisticsReport(BMPPeerMessage): @BMPMessage.register_type(BMP_MSG_PEER_DOWN_NOTIFICATION) class BMPPeerDownNotification(BMPPeerMessage): - """BMP Peer Down Notification Message + r"""BMP Peer Down Notification Message ========================== =============================================== Attribute Description @@ -440,7 +460,8 @@ class BMPPeerDownNotification(BMPPeerMessage): def __init__(self, reason, data, peer_type, is_post_policy, peer_distinguisher, peer_address, peer_as, peer_bgp_id, timestamp, version=VERSION, - type_=BMP_MSG_PEER_DOWN_NOTIFICATION, len_=None): + type_=BMP_MSG_PEER_DOWN_NOTIFICATION, len_=None, + is_adj_rib_out=False): super(BMPPeerDownNotification, self).__init__(peer_type=peer_type, @@ -452,7 +473,8 @@ class BMPPeerDownNotification(BMPPeerMessage): timestamp=timestamp, len_=len_, type_=type_, - version=version) + version=version, + is_adj_rib_out=is_adj_rib_out) self.reason = reason self.data = data @@ -498,7 +520,7 @@ class BMPPeerDownNotification(BMPPeerMessage): @BMPMessage.register_type(BMP_MSG_PEER_UP_NOTIFICATION) class BMPPeerUpNotification(BMPPeerMessage): - """BMP Peer Up Notification Message + r"""BMP Peer Up Notification Message ========================== =============================================== Attribute Description @@ -537,7 +559,7 @@ class BMPPeerUpNotification(BMPPeerMessage): peer_type, is_post_policy, peer_distinguisher, peer_address, peer_as, peer_bgp_id, timestamp, version=VERSION, type_=BMP_MSG_PEER_UP_NOTIFICATION, - len_=None): + len_=None, is_adj_rib_out=False): super(BMPPeerUpNotification, self).__init__(peer_type=peer_type, is_post_policy=is_post_policy, @@ -548,7 +570,8 @@ class BMPPeerUpNotification(BMPPeerMessage): timestamp=timestamp, len_=len_, type_=type_, - version=version) + version=version, + is_adj_rib_out=is_adj_rib_out) self.local_address = local_address self.local_port = local_port self.remote_port = remote_port @@ -605,7 +628,7 @@ class BMPPeerUpNotification(BMPPeerMessage): @BMPMessage.register_type(BMP_MSG_INITIATION) class BMPInitiation(BMPMessage): - """BMP Initiation Message + r"""BMP Initiation Message ========================== =============================================== Attribute Description @@ -669,7 +692,7 @@ class BMPInitiation(BMPMessage): @BMPMessage.register_type(BMP_MSG_TERMINATION) class BMPTermination(BMPMessage): - """BMP Termination Message + r"""BMP Termination Message ========================== =============================================== Attribute Description diff --git a/ryu/lib/packet/cfm.py b/ryu/lib/packet/cfm.py index 0e8c2cf1..cbf9999a 100644 --- a/ryu/lib/packet/cfm.py +++ b/ryu/lib/packet/cfm.py @@ -268,7 +268,7 @@ class cc_message(operation): self._opcode = CFM_CC_MESSAGE assert rdi in [0, 1] self.rdi = rdi - assert interval is not 0 + assert interval != 0 self.interval = interval self.seq_num = seq_num assert 1 <= mep_id <= 8191 diff --git a/ryu/lib/packet/ether_types.py b/ryu/lib/packet/ether_types.py index e8287d3b..ff2ba67b 100644 --- a/ryu/lib/packet/ether_types.py +++ b/ryu/lib/packet/ether_types.py @@ -26,3 +26,4 @@ ETH_TYPE_LLDP = 0x88cc ETH_TYPE_8021AH = 0x88e7 ETH_TYPE_IEEE802_3 = 0x05dc ETH_TYPE_CFM = 0x8902 +ETH_TYPE_NSH = 0x894f # RFC8300 diff --git a/ryu/lib/packet/icmpv6.py b/ryu/lib/packet/icmpv6.py index 00b883bf..0c228382 100644 --- a/ryu/lib/packet/icmpv6.py +++ b/ryu/lib/packet/icmpv6.py @@ -75,7 +75,7 @@ BLOCK_OLD_SOURCES = 6 class icmpv6(packet_base.PacketBase): - """ICMPv6 (RFC 2463) header encoder/decoder class. + r"""ICMPv6 (RFC 2463) header encoder/decoder class. An instance has the following attributes at least. Most of them are same to the on-wire counterparts but in host byte order. @@ -553,7 +553,7 @@ class nd_option_tla(nd_option_la): @nd_router_advert.register_nd_option_type class nd_option_pi(nd_option): - """ICMPv6 sub encoder/decoder class for Neighbor discovery + r"""ICMPv6 sub encoder/decoder class for Neighbor discovery Prefix Information Option. (RFC 4861) This is used with ryu.lib.packet.icmpv6.nd_router_advert. @@ -623,6 +623,50 @@ class nd_option_pi(nd_option): return six.binary_type(hdr) +@nd_router_advert.register_nd_option_type +class nd_option_mtu(nd_option): + """ICMPv6 sub encoder/decoder class for Neighbor discovery + MTU Option. (RFC 4861) + + This is used with ryu.lib.packet.icmpv6.nd_router_advert. + + An instance has the following attributes at least. + Most of them are same to the on-wire counterparts but in host byte order. + __init__ takes the corresponding args in this order. + + .. tabularcolumns:: |l|p{35em}| + + ============== ==================== + Attribute Description + ============== ==================== + mtu MTU. + ============== ==================== + """ + + _PACK_STR = '!BBHI' + _LEN = struct.calcsize(_PACK_STR) + _OPTION_LEN = _LEN // 8 + + @classmethod + def option_type(cls): + return ND_OPTION_MTU + + def __init__(self, mtu=1500): + super(nd_option_mtu, self).__init__(self.option_type(), 0) + self.mtu = mtu + + @classmethod + def parser(cls, buf, offset): + (_, _, _, mtu) = struct.unpack_from(cls._PACK_STR, buf, offset) + msg = cls(mtu) + return msg + + def serialize(self): + buf = bytearray(struct.pack( + self._PACK_STR, self.option_type(), self._OPTION_LEN, 0, self.mtu)) + return six.binary_type(buf) + + @icmpv6.register_icmpv6_type(ICMPV6_ECHO_REPLY, ICMPV6_ECHO_REQUEST) class echo(_ICMPv6Payload): """ICMPv6 sub encoder/decoder class for Echo Request and Echo Reply @@ -884,7 +928,7 @@ class mldv2_report(mld): class mldv2_report_group(stringify.StringifyMixin): - """ + r""" ICMPv6 sub encoder/decoder class for MLD v2 Lister Report Group Record messages. (RFC 3810) diff --git a/ryu/lib/packet/igmp.py b/ryu/lib/packet/igmp.py index 8935da3b..d4c9552c 100644 --- a/ryu/lib/packet/igmp.py +++ b/ryu/lib/packet/igmp.py @@ -391,7 +391,7 @@ class igmpv3_report(igmp): class igmpv3_report_group(stringify.StringifyMixin): - """ + r""" Internet Group Management Protocol(IGMP, RFC 3376) Membership Report Group Record message encoder/decoder class. diff --git a/ryu/lib/packet/ipv6.py b/ryu/lib/packet/ipv6.py index 007dc564..6ceaced3 100644 --- a/ryu/lib/packet/ipv6.py +++ b/ryu/lib/packet/ipv6.py @@ -274,7 +274,7 @@ class dst_opts(opt_header): class option(stringify.StringifyMixin): - """IPv6 (RFC 2460) Options header encoder/decoder class. + r"""IPv6 (RFC 2460) Options header encoder/decoder class. This is used with ryu.lib.packet.ipv6.hop_opts or ryu.lib.packet.ipv6.dst_opts. @@ -496,7 +496,7 @@ class routing_type3(header): @ipv6.register_header_type(inet.IPPROTO_FRAGMENT) class fragment(header): - """IPv6 (RFC 2460) fragment header encoder/decoder class. + r"""IPv6 (RFC 2460) fragment header encoder/decoder class. This is used with ryu.lib.packet.ipv6.ipv6. diff --git a/ryu/lib/packet/lldp.py b/ryu/lib/packet/lldp.py index 914f07c1..a48884d7 100644 --- a/ryu/lib/packet/lldp.py +++ b/ryu/lib/packet/lldp.py @@ -455,13 +455,12 @@ class SystemCapabilities(LLDPBasicTLV): Attribute Description ================= ===================================== buf Binary data to parse. - subtype Subtype. system_cap System Capabilities. enabled_cap Enabled Capabilities. ================= ===================================== """ - # chassis subtype(1) + system cap(2) + enabled cap(2) - _PACK_STR = '!BHH' + # system cap(2) + enabled cap(2) + _PACK_STR = '!HH' _PACK_SIZE = struct.calcsize(_PACK_STR) _LEN_MIN = _PACK_SIZE _LEN_MAX = _PACK_SIZE @@ -481,10 +480,9 @@ class SystemCapabilities(LLDPBasicTLV): def __init__(self, buf=None, *args, **kwargs): super(SystemCapabilities, self).__init__(buf, *args, **kwargs) if buf: - (self.subtype, self.system_cap, self.enabled_cap) = \ - struct.unpack(self._PACK_STR, self.tlv_info[:self._PACK_SIZE]) + (self.system_cap, self.enabled_cap) = struct.unpack( + self._PACK_STR, self.tlv_info[:self._PACK_SIZE]) else: - self.subtype = kwargs['subtype'] self.system_cap = kwargs['system_cap'] self.enabled_cap = kwargs['enabled_cap'] self.len = self._PACK_SIZE @@ -492,9 +490,8 @@ class SystemCapabilities(LLDPBasicTLV): self.typelen = (self.tlv_type << LLDP_TLV_TYPE_SHIFT) | self.len def serialize(self): - return struct.pack('!HBHH', - self.typelen, self.subtype, - self.system_cap, self.enabled_cap) + return struct.pack('!HHH', + self.typelen, self.system_cap, self.enabled_cap) @lldp.set_tlv_type(LLDP_TLV_MANAGEMENT_ADDRESS) diff --git a/ryu/lib/rpc.py b/ryu/lib/rpc.py index 7db0ebeb..f74f8846 100644 --- a/ryu/lib/rpc.py +++ b/ryu/lib/rpc.py @@ -40,8 +40,16 @@ class MessageEncoder(object): def __init__(self): super(MessageEncoder, self).__init__() - self._packer = msgpack.Packer(encoding='utf-8', use_bin_type=True) - self._unpacker = msgpack.Unpacker(encoding='utf-8') + if msgpack.version >= (1, 0, 0): + self._packer = msgpack.Packer() + # The strict_map_key=False option is required to use int keys in + # maps; it is disabled by default to prevent hash collision denial + # of service attacks (hashdos) in scenarios where an attacker can + # control the keys to be hashed. + self._unpacker = msgpack.Unpacker(strict_map_key=False) + else: + self._packer = msgpack.Packer(encoding='utf-8', use_bin_type=True) + self._unpacker = msgpack.Unpacker(encoding='utf-8') self._next_msgid = 0 def _create_msgid(self): diff --git a/ryu/lib/stringify.py b/ryu/lib/stringify.py index 94ffbbcb..e178408b 100644 --- a/ryu/lib/stringify.py +++ b/ryu/lib/stringify.py @@ -327,7 +327,7 @@ class StringifyMixin(object): @classmethod def from_jsondict(cls, dict_, decode_string=base64.b64decode, **additional_args): - """Create an instance from a JSON style dict. + r"""Create an instance from a JSON style dict. Instantiate this class with parameters specified by the dict. diff --git a/ryu/ofproto/nicira_ext.py b/ryu/ofproto/nicira_ext.py index 9e0f8873..19c8394c 100644 --- a/ryu/ofproto/nicira_ext.py +++ b/ryu/ofproto/nicira_ext.py @@ -62,6 +62,10 @@ NXAST_NAT = 36 NXAST_CONTROLLER2 = 37 NXAST_SAMPLE2 = 38 NXAST_OUTPUT_TRUNC = 39 +NXAST_CT_CLEAR = 43 +NXAST_RAW_ENCAP = 46 +NXAST_RAW_DECAP = 47 +NXAST_DEC_NSH_TTL = 48 NX_ACTION_RESUBMIT_PACK_STR = '!HHIHHB3x' NX_ACTION_RESUBMIT_SIZE = 16 @@ -296,7 +300,7 @@ NXM_IP_FRAG_NOT_LATER = (0, FLOW_NW_FRAG_LATER) def ofs_nbits(start, end): - """ + r""" The utility method for ofs_nbits This method is used in the class to set the ofs_nbits. @@ -590,6 +594,29 @@ tun_ipv6_dst IPv6 address Tunnel IPv6 destination address. eth_type_nxm = 0x86dd (IPv6) _recirc_id Integer 32bit ID for recirculation. _dp_hash Integer 32bit Flow hash computed in Datapath. +nsh_flags Integer 8bit Flags field in NSH Base Header. + Requires eth_type_nxm = 0x894f (NSH). + Since OpenFlow 1.3 and OVS v2.8. +nsh_mdtype Integer 8bit Metadata Type in NSH Base Header. + Requires eth_type_nxm = 0x894f (NSH). + Since OpenFlow 1.3 and OVS v2.8. +nsh_np Integer 8bit Next Protocol type in NSH Base Header. + Requires eth_type_nxm = 0x894f (NSH). + Since OpenFlow 1.3 and OVS v2.8. +nsh_spi Integer 32bit Service Path Identifier in NSH Service Path + Header. + Requires eth_type_nxm = 0x894f (NSH). + Since OpenFlow 1.3 and OVS v2.8. +nsh_si Integer 8bit Service Index in NSH Service Path Header. + Requires eth_type_nxm = 0x894f (NSH). + Since OpenFlow 1.3 and OVS v2.8. +nsh_c Integer 32bit Context fields in NSH Context Header. + is a number of 1-4. + Requires eth_type_nxm = 0x894f (NSH). + Since OpenFlow 1.3 and OVS v2.8. +nsh_ttl Integer 8bit TTL field in NSH Base Header. + Requires eth_type_nxm = 0x894f (NSH). + Since OpenFlow 1.3 and OVS v2.9. reg Integer 32bit Packet register. is register number 0-15. xxreg Integer 128bit Packet extended-extended register. @@ -684,6 +711,21 @@ oxm_types = [ # in wild. oxm_fields.NiciraExperimenter('_dp_hash', 0, type_desc.Int4), + # Nicira Experimenter for Network Service Header + oxm_fields.NiciraNshExperimenter('nsh_flags', 1, type_desc.Int1), + oxm_fields.NiciraNshExperimenter('nsh_mdtype', 2, type_desc.Int1), + oxm_fields.NiciraNshExperimenter('nsh_np', 3, type_desc.Int1), + # aka "nsp" + oxm_fields.NiciraNshExperimenter('nsh_spi', 4, type_desc.Int4), + # aka "nsi" + oxm_fields.NiciraNshExperimenter('nsh_si', 5, type_desc.Int1), + # aka "nshc" + oxm_fields.NiciraNshExperimenter('nsh_c1', 6, type_desc.Int4), + oxm_fields.NiciraNshExperimenter('nsh_c2', 7, type_desc.Int4), + oxm_fields.NiciraNshExperimenter('nsh_c3', 8, type_desc.Int4), + oxm_fields.NiciraNshExperimenter('nsh_c4', 9, type_desc.Int4), + oxm_fields.NiciraNshExperimenter('nsh_ttl', 10, type_desc.Int1), + # Support for matching/setting NX registers 0-15 oxm_fields.NiciraExtended1('reg0', 0, type_desc.Int4), oxm_fields.NiciraExtended1('reg1', 1, type_desc.Int4), diff --git a/ryu/ofproto/nx_actions.py b/ryu/ofproto/nx_actions.py index 89210070..bdb36406 100644 --- a/ryu/ofproto/nx_actions.py +++ b/ryu/ofproto/nx_actions.py @@ -248,7 +248,7 @@ def generate(ofp_name, ofpp_name): # For OpenFlow1.0 only class NXActionSetQueue(NXAction): - """ + r""" Set queue action This action sets the queue that should be used to queue @@ -338,7 +338,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionRegLoad(NXAction): - """ + r""" Load literal value action This action loads a literal value into a field or part of a field. @@ -405,7 +405,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionRegLoad2(NXAction): - """ + r""" Load literal value action This action loads a literal value into a field or part of a field. @@ -474,7 +474,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionNote(NXAction): - """ + r""" Note action This action does nothing at all. @@ -553,7 +553,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionSetTunnel(_NXActionSetTunnelBase): - """ + r""" Set Tunnel action This action sets the identifier (such as GRE) to the specified id. @@ -561,10 +561,9 @@ def generate(ofp_name, ofpp_name): And equivalent to the followings action of ovs-ofctl command. .. note:: - ovs-ofctl command of the OpenFlow1.0 is different from that - of OpenFlow1.2 or later. - - OpenFlow1.0 + This actions is supported by + ``OFPActionSetField`` + in OpenFlow1.2 or later. .. set_tunnel:id @@ -574,16 +573,6 @@ def generate(ofp_name, ofpp_name): | **set_tunnel**\:\ *id* | +------------------------+ - OpenFlow1.2 or later - - .. - set_field:value->tun_id - .. - - +-----------------------------------+ - | **set_field**\:\ *value*\->tun_id | - +-----------------------------------+ - ================ ====================================================== Attribute Description ================ ====================================================== @@ -600,7 +589,7 @@ def generate(ofp_name, ofpp_name): _fmt_str = '!2xI' class NXActionSetTunnel64(_NXActionSetTunnelBase): - """ + r""" Set Tunnel action This action outputs to a port that encapsulates @@ -609,10 +598,9 @@ def generate(ofp_name, ofpp_name): And equivalent to the followings action of ovs-ofctl command. .. note:: - ovs-ofctl command of the OpenFlow1.0 is different from that - of OpenFlow1.2 or later. - - OpenFlow1.0 + This actions is supported by + ``OFPActionSetField`` + in OpenFlow1.2 or later. .. set_tunnel64:id @@ -622,16 +610,6 @@ def generate(ofp_name, ofpp_name): | **set_tunnel64**\:\ *id* | +--------------------------+ - OpenFlow1.2 or later - - .. - set_field:value->tun_id - .. - - +-----------------------------------+ - | **set_field**\:\ *value*\->tun_id | - +-----------------------------------+ - ================ ====================================================== Attribute Description ================ ====================================================== @@ -648,7 +626,7 @@ def generate(ofp_name, ofpp_name): _fmt_str = '!6xQ' class NXActionRegMove(NXAction): - """ + r""" Move register action This action copies the src to dst. @@ -737,7 +715,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionResubmit(NXAction): - """ + r""" Resubmit action This action searches one of the switch's flow tables. @@ -786,7 +764,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionResubmitTable(NXAction): - """ + r""" Resubmit action This action searches one of the switch's flow tables. @@ -840,7 +818,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionOutputReg(NXAction): - """ + r""" Add output action This action outputs the packet to the OpenFlow port number read from @@ -914,7 +892,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionOutputReg2(NXAction): - """ + r""" Add output action This action outputs the packet to the OpenFlow port number read from @@ -996,7 +974,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionLearn(NXAction): - """ + r""" Adds or modifies flow action This action adds or modifies a flow in OpenFlow table. @@ -1260,7 +1238,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionController(NXAction): - """ + r""" Send packet in message action This action sends the packet to the OpenFlow controller as @@ -1325,7 +1303,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionController2(NXAction): - """ + r""" Send packet in message action This action sends the packet to the OpenFlow controller as @@ -1571,7 +1549,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionDecTtlCntIds(NXAction): - """ + r""" Decrement TTL action This action decrements TTL of IPv4 packet or @@ -1682,7 +1660,7 @@ def generate(ofp_name, ofpp_name): # For OpenFlow1.0 only class NXActionPushMpls(NXActionMplsBase): - """ + r""" Push MPLS action This action pushes a new MPLS header to the packet. @@ -1717,7 +1695,7 @@ def generate(ofp_name, ofpp_name): # For OpenFlow1.0 only class NXActionPopMpls(NXActionMplsBase): - """ + r""" Pop MPLS action This action pops the MPLS header from the packet. @@ -1752,7 +1730,7 @@ def generate(ofp_name, ofpp_name): # For OpenFlow1.0 only class NXActionSetMplsTtl(NXAction): - """ + r""" Set MPLS TTL action This action sets the MPLS TTL. @@ -1851,7 +1829,7 @@ def generate(ofp_name, ofpp_name): # For OpenFlow1.0 only class NXActionSetMplsLabel(NXAction): - """ + r""" Set MPLS Lavel action This action sets the MPLS Label. @@ -1906,7 +1884,7 @@ def generate(ofp_name, ofpp_name): # For OpenFlow1.0 only class NXActionSetMplsTc(NXAction): - """ + r""" Set MPLS Tc action This action sets the MPLS Tc. @@ -2000,7 +1978,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionStackPush(NXActionStackBase): - """ + r""" Push field action This action pushes field to top of the stack. @@ -2032,7 +2010,7 @@ def generate(ofp_name, ofpp_name): _subtype = nicira_ext.NXAST_STACK_PUSH class NXActionStackPop(NXActionStackBase): - """ + r""" Pop field action This action pops field from top of the stack. @@ -2064,7 +2042,7 @@ def generate(ofp_name, ofpp_name): _subtype = nicira_ext.NXAST_STACK_POP class NXActionSample(NXAction): - """ + r""" Sample packets action This action samples packets and sends one sample for @@ -2137,7 +2115,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionSample2(NXAction): - """ + r""" Sample packets action This action samples packets and sends one sample for @@ -2218,7 +2196,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionFinTimeout(NXAction): - """ + r""" Change TCP timeout action This action changes the idle timeout or hard timeout or @@ -2279,7 +2257,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionConjunction(NXAction): - """ + r""" Conjunctive matches action This action ties groups of individual OpenFlow flows into @@ -2342,7 +2320,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionMultipath(NXAction): - """ + r""" Select multipath link action This action selects multipath link based on the specified parameters. @@ -2528,7 +2506,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionBundle(_NXActionBundleBase): - """ + r""" Select bundle link action This action selects bundle link based on the specified parameters. @@ -2581,7 +2559,7 @@ def generate(ofp_name, ofpp_name): ofs_nbits=0, dst=0, slaves=slaves) class NXActionBundleLoad(_NXActionBundleBase): - """ + r""" Select bundle link action This action has the same behavior as the bundle action, @@ -2642,7 +2620,7 @@ def generate(ofp_name, ofpp_name): ofs_nbits, dst, slaves) class NXActionCT(NXAction): - """ + r""" Pass traffic to the connection tracker action This action sends the packet through the connection tracker. @@ -2766,8 +2744,45 @@ def generate(ofp_name, ofpp_name): a.serialize(data, len(data)) return data - class NXActionNAT(NXAction): + class NXActionCTClear(NXAction): """ + Clear connection tracking state action + + This action clears connection tracking state from packets. + + And equivalent to the followings action of ovs-ofctl command. + + .. + ct_clear + .. + + +--------------+ + | **ct_clear** | + +--------------+ + + Example:: + + actions += [parser.NXActionCTClear()] + """ + _subtype = nicira_ext.NXAST_CT_CLEAR + + _fmt_str = '!6x' + + def __init__(self, + type_=None, len_=None, experimenter=None, subtype=None): + super(NXActionCTClear, self).__init__() + + @classmethod + def parser(cls, buf): + return cls() + + def serialize_body(self): + data = bytearray() + msg_pack_into(self._fmt_str, data, 0) + return data + + class NXActionNAT(NXAction): + r""" Network address translation action This action sends the packet through the connection tracker. @@ -2930,7 +2945,7 @@ def generate(ofp_name, ofpp_name): return data class NXActionOutputTrunc(NXAction): - """ + r""" Truncate output action This action truncate a packet into the specified size and outputs it. @@ -2984,6 +2999,111 @@ def generate(ofp_name, ofpp_name): self.max_len) return data + class NXActionEncapEther(NXAction): + """ + Encap Ether + + This action encaps package with ethernet + + And equivalent to the followings action of ovs-ofctl command. + + :: + + encap(ethernet) + + Example:: + + actions += [parser.NXActionEncapEther()] + """ + _subtype = nicira_ext.NXAST_RAW_ENCAP + + _fmt_str = '!HI' + + def __init__(self, + type_=None, len_=None, vendor=None, subtype=None): + super(NXActionEncapEther, self).__init__() + self.hdr_size = 0 + self.new_pkt_type = 0x00000000 + + @classmethod + def parser(cls, buf): + return cls() + + def serialize_body(self): + data = bytearray() + msg_pack_into(self._fmt_str, data, 0, self.hdr_size, self.new_pkt_type) + return data + + class NXActionEncapNsh(NXAction): + """ + Encap nsh + + This action encaps package with nsh + + And equivalent to the followings action of ovs-ofctl command. + + :: + + encap(nsh(md_type=1)) + + Example:: + + actions += [parser.NXActionEncapNsh()] + """ + _subtype = nicira_ext.NXAST_RAW_ENCAP + + _fmt_str = '!HI' + + def __init__(self, + type_=None, len_=None, vendor=None, subtype=None): + super(NXActionEncapNsh, self).__init__() + self.hdr_size = hdr_size + self.new_pkt_type = 0x0001894F + + @classmethod + def parser(cls, buf): + return cls() + + def serialize_body(self): + data = bytearray() + msg_pack_into(self._fmt_str, data, 0, self.hdr_size, self.new_pkt_type) + return data + + class NXActionDecNshTtl(NXAction): + """ + Decrement NSH TTL action + + This action decrements the TTL in the Network Service Header(NSH). + + This action was added in OVS v2.9. + + And equivalent to the followings action of ovs-ofctl command. + + :: + + dec_nsh_ttl + + Example:: + + actions += [parser.NXActionDecNshTtl()] + """ + _subtype = nicira_ext.NXAST_DEC_NSH_TTL + + _fmt_str = '!6x' + + def __init__(self, + type_=None, len_=None, vendor=None, subtype=None): + super(NXActionDecNshTtl, self).__init__() + + @classmethod + def parser(cls, buf): + return cls() + + def serialize_body(self): + data = bytearray() + msg_pack_into(self._fmt_str, data, 0) + return data + def add_attr(k, v): v.__module__ = ofpp.__name__ # Necessary for stringify stuff setattr(ofpp, k, v) @@ -3026,12 +3146,16 @@ def generate(ofp_name, ofpp_name): 'NXActionBundle', 'NXActionBundleLoad', 'NXActionCT', + 'NXActionCTClear', 'NXActionNAT', 'NXActionOutputTrunc', '_NXFlowSpec', # exported for testing 'NXFlowSpecMatch', 'NXFlowSpecLoad', 'NXFlowSpecOutput', + 'NXActionEncapNsh', + 'NXActionEncapEther', + 'NXActionDecNshTtl', ] vars = locals() for name in classes: diff --git a/ryu/ofproto/ofproto_common.py b/ryu/ofproto/ofproto_common.py index 4f0d9956..ffdf1a4a 100644 --- a/ryu/ofproto/ofproto_common.py +++ b/ryu/ofproto/ofproto_common.py @@ -32,5 +32,6 @@ OFP_SSL_PORT_OLD = 6633 # Vendor/Experimenter IDs # https://rs.opennetworking.org/wiki/display/PUBLIC/ONF+Registry NX_EXPERIMENTER_ID = 0x00002320 # Nicira +NX_NSH_EXPERIMENTER_ID = 0x005ad650 # Nicira Ext for Network Service Header BSN_EXPERIMENTER_ID = 0x005c16c7 # Big Switch Networks ONF_EXPERIMENTER_ID = 0x4f4e4600 # OpenFlow Extensions for 1.3.X Pack 1 diff --git a/ryu/ofproto/ofproto_v1_0_parser.py b/ryu/ofproto/ofproto_v1_0_parser.py index bfc55512..a288964a 100644 --- a/ryu/ofproto/ofproto_v1_0_parser.py +++ b/ryu/ofproto/ofproto_v1_0_parser.py @@ -1258,6 +1258,8 @@ class OFPErrorMsg(MsgBase): super(OFPErrorMsg, self).__init__(datapath) self.type = type_ self.code = code + if isinstance(data, six.string_types): + data = data.encode('ascii') self.data = data @classmethod diff --git a/ryu/ofproto/ofproto_v1_2_parser.py b/ryu/ofproto/ofproto_v1_2_parser.py index 9b4dda4b..244126c3 100644 --- a/ryu/ofproto/ofproto_v1_2_parser.py +++ b/ryu/ofproto/ofproto_v1_2_parser.py @@ -141,6 +141,8 @@ class OFPErrorMsg(MsgBase): super(OFPErrorMsg, self).__init__(datapath) self.type = type_ self.code = code + if isinstance(data, six.string_types): + data = data.encode('ascii') self.data = data if self.type == ofproto.OFPET_EXPERIMENTER: self.exp_type = kwargs.get('exp_type', None) diff --git a/ryu/ofproto/ofproto_v1_3_parser.py b/ryu/ofproto/ofproto_v1_3_parser.py index 7730aa12..0324c82b 100644 --- a/ryu/ofproto/ofproto_v1_3_parser.py +++ b/ryu/ofproto/ofproto_v1_3_parser.py @@ -251,6 +251,8 @@ class OFPErrorMsg(MsgBase): super(OFPErrorMsg, self).__init__(datapath) self.type = type_ self.code = code + if isinstance(data, six.string_types): + data = data.encode('ascii') self.data = data if self.type == ofproto.OFPET_EXPERIMENTER: self.exp_type = kwargs.get('exp_type', None) diff --git a/ryu/ofproto/ofproto_v1_4_parser.py b/ryu/ofproto/ofproto_v1_4_parser.py index fca35f57..470e2013 100644 --- a/ryu/ofproto/ofproto_v1_4_parser.py +++ b/ryu/ofproto/ofproto_v1_4_parser.py @@ -262,6 +262,8 @@ class OFPErrorMsg(MsgBase): super(OFPErrorMsg, self).__init__(datapath) self.type = type_ self.code = code + if isinstance(data, six.string_types): + data = data.encode('ascii') self.data = data if self.type == ofproto.OFPET_EXPERIMENTER: self.exp_type = kwargs.get('exp_type', None) diff --git a/ryu/ofproto/ofproto_v1_5_parser.py b/ryu/ofproto/ofproto_v1_5_parser.py index 03946622..c19a7e8d 100644 --- a/ryu/ofproto/ofproto_v1_5_parser.py +++ b/ryu/ofproto/ofproto_v1_5_parser.py @@ -262,6 +262,8 @@ class OFPErrorMsg(MsgBase): super(OFPErrorMsg, self).__init__(datapath) self.type = type_ self.code = code + if isinstance(data, six.string_types): + data = data.encode('ascii') self.data = data if self.type == ofproto.OFPET_EXPERIMENTER: self.exp_type = kwargs.get('exp_type', None) diff --git a/ryu/ofproto/oxm_fields.py b/ryu/ofproto/oxm_fields.py index d2bea495..f978f5b1 100644 --- a/ryu/ofproto/oxm_fields.py +++ b/ryu/ofproto/oxm_fields.py @@ -132,6 +132,10 @@ class NiciraExperimenter(_Experimenter): experimenter_id = ofproto_common.NX_EXPERIMENTER_ID +class NiciraNshExperimenter(_Experimenter): + experimenter_id = ofproto_common.NX_NSH_EXPERIMENTER_ID + + class NiciraExtended0(_OxmClass): """Nicira Extended Match (NXM_0) diff --git a/ryu/services/protocols/bgp/application.py b/ryu/services/protocols/bgp/application.py index ed5961b8..b4ae49cf 100644 --- a/ryu/services/protocols/bgp/application.py +++ b/ryu/services/protocols/bgp/application.py @@ -14,7 +14,103 @@ # limitations under the License. """ - Defines bases classes to create a BGP application. +This module provides a convenient application for using Ryu BGPSpeaker and for +writing your BGP application. + +It reads a configuration file which includes settings for neighbors, routes +and some others. +Please refer to ``ryu/services/protocols/bgp/bgp_sample_conf.py`` for the +sample configuration. + +Usage Example:: + + $ ryu-manager ryu/services/protocols/bgp/application.py \\ + --bgp-app-config-file ryu/services/protocols/bgp/bgp_sample_conf.py + +SSH Console +=========== + +You can also use the SSH console and see the RIB and do some operations from +this console. +The SSH port and username/password can be configured by the configuration file. +You can check the help by hitting '?' key in this interface. + +Example:: + + $ ssh localhost -p 4990 + + Hello, this is Ryu BGP speaker (version 4.19). + + bgpd> # Hit '?' key + clear - allows to reset BGP connections + help - show this help + quit - exit this session + set - set runtime settings + show - shows runtime state information + bgpd> + bgpd> show rib all + Status codes: * valid, > best + Origin codes: i - IGP, e - EGP, ? - incomplete + Network Labels Next Hop Reason Metric LocPrf Path + *> 10.10.1.0/24 None 0.0.0.0 Only Path i + bgpd> + +Integration with Other Applications +=================================== + +``ryu.services.protocols.bgp.application.RyuBGPSpeaker`` will notifies the +following events to other Ryu applications. + + - ``EventBestPathChanged`` + - ``EventAdjRibInChanged`` + - ``EventPeerDown`` + - ``EventPeerUp`` + +To catch these events, specify ``@set_ev_cls()`` decorator to the event +handlers in the Ryu applications. + +Example Application:: + + # my_bgp_app.py + + from ryu.base import app_manager + from ryu.controller.handler import set_ev_cls + from ryu.services.protocols.bgp import application as bgp_application + + + class MyBGPApp(app_manager.RyuApp): + _CONTEXTS = { + 'ryubgpspeaker': bgp_application.RyuBGPSpeaker, + } + + def __init__(self, *args, **kwargs): + super(MyBGPApp, self).__init__(*args, **kwargs) + + # Stores "ryu.services.protocols.bgp.application.RyuBGPSpeaker" + # instance in order to call the APIs of + # "ryu.services.protocols.bgp.bgpspeaker.BGPSpeaker" via + # "self.app.speaker". + # Please note at this time, "BGPSpeaker" is NOT instantiated yet. + self.app = kwargs['ryubgpspeaker'] + + @set_ev_cls(bgp_application.EventBestPathChanged) + def _best_patch_changed_handler(self, ev): + self.logger.info( + 'Best path changed: is_withdraw=%s, path=%s', + ev.is_withdraw, ev.path) + +Usage Example:: + + $ ryu-manager my_bgp_app.py \\ + --bgp-app-config-file ryu/services/protocols/bgp/bgp_sample_conf.py + +.. note:: + + For the APIs for ``ryu.services.protocols.bgp.bgpspeaker.BGPSpeaker``, + please refer to :doc:`../library_bgp_speaker_ref`. + +API Reference +============= """ import logging @@ -101,6 +197,33 @@ class EventBestPathChanged(EventBase): self.is_withdraw = is_withdraw +class EventAdjRibInChanged(EventBase): + """ + Event called when any adj-RIB-in path is changed due to UPDATE messages + or remote peer's down. + + This event is the wrapper for ``adj_rib_in_change_handler`` of + ``bgpspeaker.BGPSpeaker``. + + ``path`` attribute contains an instance of ``info_base.base.Path`` + subclasses. + + If ``is_withdraw`` attribute is ``True``, ``path`` attribute has the + information of the withdraw route. + + ``peer_ip`` is the peer's IP address who sent this path. + + ``peer_as`` is the peer's AS number who sent this path. + """ + + def __init__(self, path, is_withdraw, peer_ip, peer_as): + super(EventAdjRibInChanged, self).__init__() + self.path = path + self.is_withdraw = is_withdraw + self.peer_ip = peer_ip + self.peer_as = peer_as + + class EventPeerDown(EventBase): """ Event called when the session to the remote peer goes down. @@ -140,37 +263,10 @@ class EventPeerUp(EventBase): class RyuBGPSpeaker(RyuApp): """ Base application for implementing BGP applications. - - This application will notifies - - ``EventBestPathChanged`` - - ``EventPeerDown`` - - ``EventPeerUp`` - to other BGP applications. - To catch these events, specify ``@set_ev_cls()`` decorator to the event - handlers in the Ryu applications. - - Example:: - - ... - from ryu.base import app_manager - from ryu.controller.handler import set_ev_cls - from ryu.services.protocols.bgp import application as bgp_application - ... - - class MyBGPApp(app_manager.RyuApp): - _CONTEXTS = { - 'ryubgpspeaker': bgp_application.RyuBGPSpeaker, - } - - ... - @set_ev_cls(bgp_application.EventBestPathChanged) - def _best_patch_changed_handler(self, ev): - self.logger.info( - 'Best path changed: is_withdraw=%s, path=%s', - ev.is_withdraw, ev.path) """ _EVENTS = [ EventBestPathChanged, + EventAdjRibInChanged, EventPeerDown, EventPeerUp, ] @@ -237,6 +333,8 @@ class RyuBGPSpeaker(RyuApp): # Set event notify handlers if no corresponding handler specified. settings.setdefault( 'best_path_change_handler', self._notify_best_path_changed_event) + settings.setdefault( + 'adj_rib_in_change_handler', self._notify_adj_rib_in_changed_event) settings.setdefault( 'peer_down_handler', self._notify_peer_down_event) settings.setdefault( @@ -268,6 +366,10 @@ class RyuBGPSpeaker(RyuApp): ev = EventBestPathChanged(ev.path, ev.is_withdraw) self.send_event_to_observers(ev) + def _notify_adj_rib_in_changed_event(self, ev, peer_ip, peer_as): + ev = EventAdjRibInChanged(ev.path, ev.is_withdraw, peer_ip, peer_as) + self.send_event_to_observers(ev) + def _notify_peer_down_event(self, remote_ip, remote_as): ev = EventPeerDown(remote_ip, remote_as) self.send_event_to_observers(ev) diff --git a/ryu/services/protocols/bgp/bgpspeaker.py b/ryu/services/protocols/bgp/bgpspeaker.py index 14e5eed9..2f53f636 100644 --- a/ryu/services/protocols/bgp/bgpspeaker.py +++ b/ryu/services/protocols/bgp/bgpspeaker.py @@ -68,6 +68,7 @@ from ryu.services.protocols.bgp.api.prefix import ( FLOWSPEC_FAMILY_L2VPN, FLOWSPEC_RULES, FLOWSPEC_ACTIONS) +from ryu.services.protocols.bgp.model import ReceivedRoute from ryu.services.protocols.bgp.rtconf.common import LOCAL_AS from ryu.services.protocols.bgp.rtconf.common import ROUTER_ID from ryu.services.protocols.bgp.rtconf.common import CLUSTER_ID @@ -111,21 +112,23 @@ from ryu.services.protocols.bgp.rtconf.neighbors import ( DEFAULT_CAP_MBGP_VPNV4FS, DEFAULT_CAP_MBGP_VPNV6FS, DEFAULT_CAP_MBGP_L2VPNFS, + DEFAULT_CAP_ENHANCED_REFRESH, + DEFAULT_CAP_FOUR_OCTET_AS_NUMBER, + DEFAULT_CONNECT_MODE, + REMOTE_PORT, + DEFAULT_BGP_PORT, + PEER_NEXT_HOP, + PASSWORD, + DEFAULT_IS_ROUTE_SERVER_CLIENT, + IS_ROUTE_SERVER_CLIENT, + DEFAULT_IS_ROUTE_REFLECTOR_CLIENT, + IS_ROUTE_REFLECTOR_CLIENT, + DEFAULT_IS_NEXT_HOP_SELF, + IS_NEXT_HOP_SELF, + CONNECT_MODE, + LOCAL_ADDRESS, + LOCAL_PORT, ) -from ryu.services.protocols.bgp.rtconf.neighbors import ( - DEFAULT_CAP_ENHANCED_REFRESH, DEFAULT_CAP_FOUR_OCTET_AS_NUMBER) -from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CONNECT_MODE -from ryu.services.protocols.bgp.rtconf.neighbors import PEER_NEXT_HOP -from ryu.services.protocols.bgp.rtconf.neighbors import PASSWORD -from ryu.services.protocols.bgp.rtconf.neighbors import ( - DEFAULT_IS_ROUTE_SERVER_CLIENT, IS_ROUTE_SERVER_CLIENT) -from ryu.services.protocols.bgp.rtconf.neighbors import ( - DEFAULT_IS_ROUTE_REFLECTOR_CLIENT, IS_ROUTE_REFLECTOR_CLIENT) -from ryu.services.protocols.bgp.rtconf.neighbors import ( - DEFAULT_IS_NEXT_HOP_SELF, IS_NEXT_HOP_SELF) -from ryu.services.protocols.bgp.rtconf.neighbors import CONNECT_MODE -from ryu.services.protocols.bgp.rtconf.neighbors import LOCAL_ADDRESS -from ryu.services.protocols.bgp.rtconf.neighbors import LOCAL_PORT from ryu.services.protocols.bgp.rtconf.vrfs import SUPPORTED_VRF_RF from ryu.services.protocols.bgp.info_base.base import Filter from ryu.services.protocols.bgp.info_base.ipv4 import Ipv4Path @@ -220,12 +223,82 @@ class EventPrefix(object): class BGPSpeaker(object): + """Class to provide the APIs of Ryu BGP Speaker. + + ``as_number`` specifies an Autonomous Number. It must be an integer + between 1 and 65535. + + ``router_id`` specifies BGP router identifier. It must be the + string representation of an IPv4 address (e.g. 10.0.0.1). + + ``bgp_server_host`` specifies a list of TCP listen host addresses. + + ``bgp_server_port`` specifies TCP listen port number. 179 is + used if not specified. + + ``refresh_stalepath_time`` causes the BGP speaker to remove + stale routes from the BGP table after the timer expires, even + if the speaker does not receive a Router-Refresh End-of-RIB + message. This feature is disabled (not implemented yet). + + ``refresh_max_eor_time`` causes the BGP speaker to generate a + Route-Refresh End-of-RIB message if it was not able to + generate one due to route flapping. This feature is disabled + (not implemented yet). + + ``best_path_change_handler``, if specified, is called when any + best remote path is changed due to an update message or remote + peer down. The handler is supposed to take one argument, the + instance of an EventPrefix class instance. + + ``adj_rib_in_change_handler``, if specified, is called when any + adj-RIB-in path is changed due to an update message or remote + peer down. The given handler should take three argument, the + instance of an EventPrefix class instance, str type peer's IP address + and int type peer's AS number. + + ``peer_down_handler``, if specified, is called when BGP peering + session goes down. + + ``peer_up_handler``, if specified, is called when BGP peering + session goes up. + + ``ssh_console`` specifies whether or not SSH CLI need to be started. + + ``ssh_port`` specifies the port number for SSH CLI server. + The default is bgp.operator.ssh.DEFAULT_SSH_PORT. + + ``ssh_host`` specifies the IP address for SSH CLI server. + The default is bgp.operator.ssh.DEFAULT_SSH_HOST. + + ``ssh_host_key`` specifies the path to the host key added to + the keys list used by SSH CLI server. + The default is bgp.operator.ssh.DEFAULT_SSH_HOST_KEY. + + ``label_range`` specifies the range of MPLS labels generated + automatically. + + ``allow_local_as_in_count`` maximum number of local AS number + occurrences in AS_PATH. This option is useful for e.g. auto RD/RT + configurations in leaf/spine architecture with shared AS numbers. + The default is 0 and means "local AS number is not allowed in + AS_PATH". To allow local AS, 3 is recommended (Cisco's default). + + ``cluster_id`` specifies the cluster identifier for Route Reflector. + It must be the string representation of an IPv4 address. + If omitted, "router_id" is used for this field. + + ``local_pref`` specifies the default local preference. It must be an + integer. + """ + def __init__(self, as_number, router_id, bgp_server_hosts=DEFAULT_BGP_SERVER_HOSTS, bgp_server_port=DEFAULT_BGP_SERVER_PORT, refresh_stalepath_time=DEFAULT_REFRESH_STALEPATH_TIME, refresh_max_eor_time=DEFAULT_REFRESH_MAX_EOR_TIME, best_path_change_handler=None, + adj_rib_in_change_handler=None, peer_down_handler=None, peer_up_handler=None, ssh_console=False, @@ -234,70 +307,6 @@ class BGPSpeaker(object): allow_local_as_in_count=0, cluster_id=None, local_pref=DEFAULT_LOCAL_PREF): - """Create a new BGPSpeaker object with as_number and router_id to - listen on bgp_server_port. - - ``as_number`` specifies an Autonomous Number. It must be an integer - between 1 and 65535. - - ``router_id`` specifies BGP router identifier. It must be the - string representation of an IPv4 address (e.g. 10.0.0.1). - - ``bgp_server_host`` specifies a list of TCP listen host addresses. - - ``bgp_server_port`` specifies TCP listen port number. 179 is - used if not specified. - - ``refresh_stalepath_time`` causes the BGP speaker to remove - stale routes from the BGP table after the timer expires, even - if the speaker does not receive a Router-Refresh End-of-RIB - message. This feature is disabled (not implemented yet). - - ``refresh_max_eor_time`` causes the BGP speaker to generate a - Route-Refresh End-of-RIB message if it was not able to - generate one due to route flapping. This feature is disabled - (not implemented yet). - - ``best_path_change_handler``, if specified, is called when any - best remote path is changed due to an update message or remote - peer down. The handler is supposed to take one argument, the - instance of an EventPrefix class instance. - - ``peer_down_handler``, if specified, is called when BGP peering - session goes down. - - ``peer_up_handler``, if specified, is called when BGP peering - session goes up. - - ``ssh_console`` specifies whether or not SSH CLI need to be started. - - ``ssh_port`` specifies the port number for SSH CLI server. - The default is bgp.operator.ssh.DEFAULT_SSH_PORT. - - ``ssh_host`` specifies the IP address for SSH CLI server. - The default is bgp.operator.ssh.DEFAULT_SSH_HOST. - - ``ssh_host_key`` specifies the path to the host key added to - the keys list used by SSH CLI server. - The default is bgp.operator.ssh.DEFAULT_SSH_HOST_KEY. - - ``label_range`` specifies the range of MPLS labels generated - automatically. - - ``allow_local_as_in_count`` maximum number of local AS number - occurrences in AS_PATH. This option is useful for e.g. auto RD/RT - configurations in leaf/spine architecture with shared AS numbers. - The default is 0 and means "local AS number is not allowed in - AS_PATH". To allow local AS, 3 is recommended (Cisco's default). - - ``cluster_id`` specifies the cluster identifier for Route Reflector. - It must be the string representation of an IPv4 address. - If omitted, "router_id" is used for this field. - - ``local_pref`` specifies the default local preference. It must be an - integer. - """ - super(BGPSpeaker, self).__init__() settings = { @@ -315,6 +324,7 @@ class BGPSpeaker(object): self._core_start(settings) self._init_signal_listeners() self._best_path_change_handler = best_path_change_handler + self._adj_rib_in_change_handler = adj_rib_in_change_handler self._peer_down_handler = peer_down_handler self._peer_up_handler = peer_up_handler if ssh_console: @@ -351,6 +361,15 @@ class BGPSpeaker(object): if self._best_path_change_handler: self._best_path_change_handler(ev) + def _notify_adj_rib_in_changed(self, peer, route): + if not isinstance(route, ReceivedRoute): + return + + if self._adj_rib_in_change_handler: + self._adj_rib_in_change_handler( + EventPrefix(route.path, route.path.is_withdraw), + peer.ip_address, peer.remote_as) + def _init_signal_listeners(self): CORE_MANAGER.get_core_service()._signal_bus.register_listener( BgpSignalBus.BGP_BEST_PATH_CHANGED, @@ -358,6 +377,12 @@ class BGPSpeaker(object): self._notify_best_path_changed(info['path'], info['is_withdraw']) ) + CORE_MANAGER.get_core_service()._signal_bus.register_listener( + BgpSignalBus.BGP_ADJ_RIB_IN_CHANGED, + lambda _, info: + self._notify_adj_rib_in_changed(info['peer'], + info['received_route']) + ) CORE_MANAGER.get_core_service()._signal_bus.register_listener( BgpSignalBus.BGP_ADJ_DOWN, lambda _, info: @@ -383,6 +408,7 @@ class BGPSpeaker(object): call('core.stop') def neighbor_add(self, address, remote_as, + remote_port=DEFAULT_BGP_PORT, enable_ipv4=DEFAULT_CAP_MBGP_IPV4, enable_ipv6=DEFAULT_CAP_MBGP_IPV6, enable_vpnv4=DEFAULT_CAP_MBGP_VPNV4, @@ -414,6 +440,8 @@ class BGPSpeaker(object): ``remote_as`` specifies the AS number of the peer. It must be an integer between 1 and 65535. + ``remote_port`` specifies the TCP port number of the peer. + ``enable_ipv4`` enables IPv4 address family for this neighbor. @@ -490,6 +518,7 @@ class BGPSpeaker(object): bgp_neighbor = { neighbors.IP_ADDRESS: address, neighbors.REMOTE_AS: remote_as, + REMOTE_PORT: remote_port, PEER_NEXT_HOP: next_hop, PASSWORD: password, IS_ROUTE_SERVER_CLIENT: is_route_server_client, diff --git a/ryu/services/protocols/bgp/net_ctrl.py b/ryu/services/protocols/bgp/net_ctrl.py index 92a8e71e..5c79d3f8 100644 --- a/ryu/services/protocols/bgp/net_ctrl.py +++ b/ryu/services/protocols/bgp/net_ctrl.py @@ -101,8 +101,16 @@ class RpcSession(Activity): def __init__(self, sock, outgoing_msg_sink_iter): self.peer_name = str(sock.getpeername()) super(RpcSession, self).__init__(self.NAME_FMT % self.peer_name) - self._packer = msgpack.Packer(encoding='utf-8') - self._unpacker = msgpack.Unpacker(encoding='utf-8') + if msgpack.version >= (1, 0, 0): + self._packer = msgpack.Packer() + # The strict_map_key=False option is required to use int keys in + # maps; it is disabled by default to prevent hash collision denial + # of service attacks (hashdos) in scenarios where an attacker can + # control the keys to be hashed. + self._unpacker = msgpack.Unpacker(strict_map_key=False) + else: + self._packer = msgpack.Packer(encoding='utf-8', use_bin_type=True) + self._unpacker = msgpack.Unpacker(encoding='utf-8') self._next_msgid = 0 self._socket = sock self._outgoing_msg_sink_iter = outgoing_msg_sink_iter diff --git a/ryu/services/protocols/bgp/peer.py b/ryu/services/protocols/bgp/peer.py index 70b486c0..f41715eb 100644 --- a/ryu/services/protocols/bgp/peer.py +++ b/ryu/services/protocols/bgp/peer.py @@ -989,37 +989,32 @@ class Peer(Source, Sink, NeighborConfListener, Activity): elif self.is_route_server_client: nlri_list = [path.nlri] new_pathattr.extend(pathattr_map.values()) - elif self.is_route_reflector_client: - nlri_list = [path.nlri] + else: + if self.is_route_reflector_client: + # Append ORIGINATOR_ID attribute if not already exist. + if BGP_ATTR_TYPE_ORIGINATOR_ID not in pathattr_map: + originator_id = path.source + if originator_id is None: + originator_id = self._common_conf.router_id + elif isinstance(path.source, Peer): + originator_id = path.source.ip_address + new_pathattr.append( + BGPPathAttributeOriginatorId(value=originator_id)) - # Append ORIGINATOR_ID attribute if not already exists. - if BGP_ATTR_TYPE_ORIGINATOR_ID not in pathattr_map: - originator_id = path.source - if originator_id is None: - originator_id = self._common_conf.router_id - elif isinstance(path.source, Peer): - originator_id = path.source.ip_address - new_pathattr.append( - BGPPathAttributeOriginatorId(value=originator_id)) - - # Append CLUSTER_LIST attribute if not already exists. - if BGP_ATTR_TYPE_CLUSTER_LIST not in pathattr_map: - new_pathattr.append( - BGPPathAttributeClusterList( - [self._common_conf.cluster_id])) - - for t, path_attr in pathattr_map.items(): - if t == BGP_ATTR_TYPE_CLUSTER_LIST: - # Append own CLUSTER_ID into CLUSTER_LIST attribute - # if already exists. - cluster_list = list(path_attr.value) + # Preppend own CLUSTER_ID into CLUSTER_LIST attribute if exist. + # Otherwise append CLUSTER_LIST attribute. + cluster_lst_attr = pathattr_map.get(BGP_ATTR_TYPE_CLUSTER_LIST) + if cluster_lst_attr: + cluster_list = list(cluster_lst_attr.value) if self._common_conf.cluster_id not in cluster_list: - cluster_list.append(self._common_conf.cluster_id) + cluster_list.insert(0, self._common_conf.cluster_id) new_pathattr.append( BGPPathAttributeClusterList(cluster_list)) else: - new_pathattr.append(path_attr) - else: + new_pathattr.append( + BGPPathAttributeClusterList( + [self._common_conf.cluster_id])) + # Supported and un-supported/unknown attributes. origin_attr = None nexthop_attr = None @@ -1288,7 +1283,7 @@ class Peer(Source, Sink, NeighborConfListener, Activity): else: bind_addr = None peer_address = (self._neigh_conf.ip_address, - const.STD_BGP_SERVER_PORT_NUM) + self._neigh_conf.port) if bind_addr: LOG.debug('%s trying to connect from' @@ -2005,8 +2000,8 @@ class Peer(Source, Sink, NeighborConfListener, Activity): # Open/Notification messages are currently handled by protocol and # nothing is done inside peer, so should not see them here. raise ValueError('Peer does not support handling of %s' - ' message during % state' % - (msg, self.state.bgp_state())) + ' message during %s state' % + (msg, self.state.bgp_state)) def _handle_err_sor_msg(self, afi, safi): # Check if ERR capability is enabled for this peer. diff --git a/ryu/services/protocols/bgp/rtconf/neighbors.py b/ryu/services/protocols/bgp/rtconf/neighbors.py index 6c481a49..b0853f10 100644 --- a/ryu/services/protocols/bgp/rtconf/neighbors.py +++ b/ryu/services/protocols/bgp/rtconf/neighbors.py @@ -45,6 +45,7 @@ from ryu.lib.packet.bgp import BGP_CAP_MULTIPROTOCOL from ryu.lib.packet.bgp import BGP_CAP_ROUTE_REFRESH from ryu.services.protocols.bgp.base import OrderedDict +from ryu.services.protocols.bgp.constants import STD_BGP_SERVER_PORT_NUM from ryu.services.protocols.bgp.rtconf.base import ADVERTISE_PEER_AS from ryu.services.protocols.bgp.rtconf.base import BaseConf from ryu.services.protocols.bgp.rtconf.base import BaseConfListener @@ -88,6 +89,7 @@ LOG = logging.getLogger('bgpspeaker.rtconf.neighbor') # Various neighbor settings. REMOTE_AS = 'remote_as' IP_ADDRESS = 'ip_address' +REMOTE_PORT = 'remote_port' ENABLED = 'enabled' CHANGES = 'changes' LOCAL_ADDRESS = 'local_address' @@ -108,6 +110,7 @@ CONNECT_MODE_PASSIVE = 'passive' CONNECT_MODE_BOTH = 'both' # Default value constants. +DEFAULT_BGP_PORT = STD_BGP_SERVER_PORT_NUM DEFAULT_CAP_GR_NULL = True DEFAULT_CAP_REFRESH = True DEFAULT_CAP_ENHANCED_REFRESH = False @@ -213,6 +216,13 @@ def validate_remote_as(asn): return asn +@validate(name=REMOTE_PORT) +def validate_remote_port(port): + if not isinstance(port, numbers.Integral): + raise ConfigTypeError(desc='Invalid remote port: %s' % port) + return port + + def valid_prefix_filter(filter_): policy = filter_.get('policy', None) if policy == 'permit': @@ -339,7 +349,7 @@ class NeighborConf(ConfWithId, ConfWithStats): CAP_MBGP_IPV4FS, CAP_MBGP_VPNV4FS, CAP_MBGP_IPV6FS, CAP_MBGP_VPNV6FS, CAP_MBGP_L2VPNFS, - RTC_AS, HOLD_TIME, + RTC_AS, HOLD_TIME, REMOTE_PORT, ENABLED, MULTI_EXIT_DISC, MAX_PREFIXES, ADVERTISE_PEER_AS, SITE_OF_ORIGINS, LOCAL_ADDRESS, LOCAL_PORT, LOCAL_AS, @@ -406,6 +416,8 @@ class NeighborConf(ConfWithId, ConfWithStats): DEFAULT_IS_NEXT_HOP_SELF, **kwargs) self._settings[CONNECT_MODE] = compute_optional_conf( CONNECT_MODE, DEFAULT_CONNECT_MODE, **kwargs) + self._settings[REMOTE_PORT] = compute_optional_conf( + REMOTE_PORT, DEFAULT_BGP_PORT, **kwargs) # We do not have valid default MED value. # If no MED attribute is provided then we do not have to use MED. @@ -483,6 +495,10 @@ class NeighborConf(ConfWithId, ConfWithStats): def ip_address(self): return self._settings[IP_ADDRESS] + @property + def port(self): + return self._settings[REMOTE_PORT] + @property def host_bind_ip(self): return self._settings[LOCAL_ADDRESS] diff --git a/ryu/services/protocols/ovsdb/client.py b/ryu/services/protocols/ovsdb/client.py index 6ea36842..3f8b4304 100644 --- a/ryu/services/protocols/ovsdb/client.py +++ b/ryu/services/protocols/ovsdb/client.py @@ -319,7 +319,7 @@ class RemoteOvsdb(app_manager.RyuApp): fsm.connected(now()) - session = jsonrpc.Session(fsm, connection) + session = jsonrpc.Session(fsm, connection, fsm.get_name()) idl = Idl(session, schemas[0]) system_id = discover_system_id(idl) diff --git a/ryu/tests/integrated/common/install_docker_test_pkg_for_travis.sh b/ryu/tests/integrated/common/install_docker_test_pkg_for_github_actions.sh similarity index 100% rename from ryu/tests/integrated/common/install_docker_test_pkg_for_travis.sh rename to ryu/tests/integrated/common/install_docker_test_pkg_for_github_actions.sh diff --git a/ryu/tests/integrated/test_vrrp_linux_multi.py b/ryu/tests/integrated/test_vrrp_linux_multi.py index dca70c47..ac5c3252 100644 --- a/ryu/tests/integrated/test_vrrp_linux_multi.py +++ b/ryu/tests/integrated/test_vrrp_linux_multi.py @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -""" +r""" Usage: PYTHONPATH=. ./bin/ryu-manager --verbose \ ryu.services.protocols.vrrp.dumper \ diff --git a/ryu/tests/integrated/test_vrrp_multi.py b/ryu/tests/integrated/test_vrrp_multi.py index 6aee6395..a26d949a 100644 --- a/ryu/tests/integrated/test_vrrp_multi.py +++ b/ryu/tests/integrated/test_vrrp_multi.py @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -""" +r""" Usage: PYTHONPATH=. ./bin/ryu-manager --verbose \ ryu.topology.switches \ diff --git a/ryu/tests/packet_data/of13/ovs-ofctl-of13-action_ct_clear.packet b/ryu/tests/packet_data/of13/ovs-ofctl-of13-action_ct_clear.packet new file mode 100644 index 00000000..13bc3901 Binary files /dev/null and b/ryu/tests/packet_data/of13/ovs-ofctl-of13-action_ct_clear.packet differ diff --git a/ryu/tests/packet_data_generator3/gen.py b/ryu/tests/packet_data_generator3/gen.py index 0216dc42..7f2fbeef 100644 --- a/ryu/tests/packet_data_generator3/gen.py +++ b/ryu/tests/packet_data_generator3/gen.py @@ -131,6 +131,13 @@ MESSAGES = [ 'importance=39032'] + ['dl_type=0x86dd'] + ['actions=ct(commit,nat(dst=2001:1::1-2001:1::ffff)'])}, + {'name': 'action_ct_clear', + 'versions': [4], + 'cmd': 'add-flow', + 'args': (['table=3,', + 'importance=39032'] + + ['dl_type=0x0800,ct_state=+trk'] + + ['actions=ct_clear'])}, {'name': 'action_note', 'versions': [4], 'cmd': 'add-flow', @@ -312,7 +319,7 @@ if __name__ == '__main__': stdout=subprocess.PIPE) has_names = False try: - ver_tuple = re.search('\s(\d+)\.(\d+)(\.\d*|\s*$)', + ver_tuple = re.search(r'\s(\d+)\.(\d+)(\.\d*|\s*$)', ovs_version.stdout.readline().decode()).groups() if int(ver_tuple[0]) > 2 or \ int(ver_tuple[0]) == 2 and int(ver_tuple[1]) >= 8: diff --git a/ryu/tests/switch/of13/action/25_SET_FIELD/29_ICMPV6_TYPE.json b/ryu/tests/switch/of13/action/25_SET_FIELD/29_ICMPV6_TYPE.json index 56240928..5c55502f 100644 --- a/ryu/tests/switch/of13/action/25_SET_FIELD/29_ICMPV6_TYPE.json +++ b/ryu/tests/switch/of13/action/25_SET_FIELD/29_ICMPV6_TYPE.json @@ -62,12 +62,12 @@ "ingress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=135)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=135)" ] } ] @@ -135,13 +135,13 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=135)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=135)" ] } ] @@ -245,12 +245,12 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34887)", "mpls(bsb=1, label=100, exp=3, ttl=64)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=135)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=135)" ] } ] @@ -353,12 +353,12 @@ "itag(sid=100)", "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=135)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=135)" ] } ] diff --git a/ryu/tests/switch/of13/action/25_SET_FIELD/30_ICMPV6_CODE.json b/ryu/tests/switch/of13/action/25_SET_FIELD/30_ICMPV6_CODE.json index 9a8570aa..972455ec 100644 --- a/ryu/tests/switch/of13/action/25_SET_FIELD/30_ICMPV6_CODE.json +++ b/ryu/tests/switch/of13/action/25_SET_FIELD/30_ICMPV6_CODE.json @@ -62,12 +62,12 @@ "ingress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=1,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=1,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -135,13 +135,13 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=1,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=1,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -245,12 +245,12 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34887)", "mpls(bsb=1, label=100, exp=3, ttl=64)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=1,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=1,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -353,12 +353,12 @@ "itag(sid=100)", "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=1,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=1,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] diff --git a/ryu/tests/switch/of13/match/29_ICMPV6_TYPE.json b/ryu/tests/switch/of13/match/29_ICMPV6_TYPE.json index db0dd123..182ee593 100644 --- a/ryu/tests/switch/of13/match/29_ICMPV6_TYPE.json +++ b/ryu/tests/switch/of13/match/29_ICMPV6_TYPE.json @@ -52,12 +52,12 @@ "ingress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -115,12 +115,12 @@ "ingress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "PACKET_IN":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -238,13 +238,13 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -303,13 +303,13 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "PACKET_IN":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -464,12 +464,12 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34887)", "mpls(bsb=1, label=100, exp=3, ttl=64)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -564,12 +564,12 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34887)", "mpls(bsb=1, label=100, exp=3, ttl=64)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "PACKET_IN":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -759,12 +759,12 @@ "itag(sid=100)", "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -858,12 +858,12 @@ "itag(sid=100)", "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "PACKET_IN":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] diff --git a/ryu/tests/switch/of13/match/30_ICMPV6_CODE.json b/ryu/tests/switch/of13/match/30_ICMPV6_CODE.json index 739678d4..aee2edf7 100644 --- a/ryu/tests/switch/of13/match/30_ICMPV6_CODE.json +++ b/ryu/tests/switch/of13/match/30_ICMPV6_CODE.json @@ -52,12 +52,12 @@ "ingress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -115,12 +115,12 @@ "ingress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "PACKET_IN":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -238,13 +238,13 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -303,13 +303,13 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "PACKET_IN":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -464,12 +464,12 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34887)", "mpls(bsb=1, label=100, exp=3, ttl=64)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -564,12 +564,12 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34887)", "mpls(bsb=1, label=100, exp=3, ttl=64)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "PACKET_IN":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -759,12 +759,12 @@ "itag(sid=100)", "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -858,12 +858,12 @@ "itag(sid=100)", "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "PACKET_IN":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] diff --git a/ryu/tests/switch/of14/action/25_SET_FIELD/29_ICMPV6_TYPE.json b/ryu/tests/switch/of14/action/25_SET_FIELD/29_ICMPV6_TYPE.json index 56240928..5c55502f 100644 --- a/ryu/tests/switch/of14/action/25_SET_FIELD/29_ICMPV6_TYPE.json +++ b/ryu/tests/switch/of14/action/25_SET_FIELD/29_ICMPV6_TYPE.json @@ -62,12 +62,12 @@ "ingress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=135)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=135)" ] } ] @@ -135,13 +135,13 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=135)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=135)" ] } ] @@ -245,12 +245,12 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34887)", "mpls(bsb=1, label=100, exp=3, ttl=64)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=135)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=135)" ] } ] @@ -353,12 +353,12 @@ "itag(sid=100)", "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=135)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=135)" ] } ] diff --git a/ryu/tests/switch/of14/action/25_SET_FIELD/30_ICMPV6_CODE.json b/ryu/tests/switch/of14/action/25_SET_FIELD/30_ICMPV6_CODE.json index 9a8570aa..972455ec 100644 --- a/ryu/tests/switch/of14/action/25_SET_FIELD/30_ICMPV6_CODE.json +++ b/ryu/tests/switch/of14/action/25_SET_FIELD/30_ICMPV6_CODE.json @@ -62,12 +62,12 @@ "ingress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=1,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=1,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -135,13 +135,13 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=1,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=1,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -245,12 +245,12 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34887)", "mpls(bsb=1, label=100, exp=3, ttl=64)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=1,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=1,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -353,12 +353,12 @@ "itag(sid=100)", "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=1,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=1,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] diff --git a/ryu/tests/switch/of14/match/29_ICMPV6_TYPE.json b/ryu/tests/switch/of14/match/29_ICMPV6_TYPE.json index db0dd123..182ee593 100644 --- a/ryu/tests/switch/of14/match/29_ICMPV6_TYPE.json +++ b/ryu/tests/switch/of14/match/29_ICMPV6_TYPE.json @@ -52,12 +52,12 @@ "ingress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -115,12 +115,12 @@ "ingress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "PACKET_IN":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -238,13 +238,13 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -303,13 +303,13 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "PACKET_IN":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -464,12 +464,12 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34887)", "mpls(bsb=1, label=100, exp=3, ttl=64)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -564,12 +564,12 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34887)", "mpls(bsb=1, label=100, exp=3, ttl=64)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "PACKET_IN":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -759,12 +759,12 @@ "itag(sid=100)", "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -858,12 +858,12 @@ "itag(sid=100)", "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "PACKET_IN":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] diff --git a/ryu/tests/switch/of14/match/30_ICMPV6_CODE.json b/ryu/tests/switch/of14/match/30_ICMPV6_CODE.json index 739678d4..aee2edf7 100644 --- a/ryu/tests/switch/of14/match/30_ICMPV6_CODE.json +++ b/ryu/tests/switch/of14/match/30_ICMPV6_CODE.json @@ -52,12 +52,12 @@ "ingress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -115,12 +115,12 @@ "ingress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "PACKET_IN":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -238,13 +238,13 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -303,13 +303,13 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "PACKET_IN":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=33024)", "vlan(pcp=3, cfi=0, vid=100, ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -464,12 +464,12 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34887)", "mpls(bsb=1, label=100, exp=3, ttl=64)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -564,12 +564,12 @@ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34887)", "mpls(bsb=1, label=100, exp=3, ttl=64)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "PACKET_IN":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -759,12 +759,12 @@ "itag(sid=100)", "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "egress":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] @@ -858,12 +858,12 @@ "itag(sid=100)", "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ], "PACKET_IN":[ "ethernet(dst='22:22:22:22:22:22', src='12:11:11:11:11:11', ethertype=34525)", "ipv6(dst='20::20', flow_label=100, src='10::10', nxt=58, hop_limit=64, traffic_class=32)", - "icmpv6(code=0,data=echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" + "icmpv6(code=0,data=icmpv6echo(data=b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f !\"#$%&\\'()*+,-./0123'),type_=128)" ] } ] diff --git a/ryu/tests/switch/tester.py b/ryu/tests/switch/tester.py index d57d8de5..8ff9e966 100644 --- a/ryu/tests/switch/tester.py +++ b/ryu/tests/switch/tester.py @@ -47,13 +47,31 @@ from ryu.ofproto import ofproto_v1_5 # import all packet libraries. PKT_LIB_PATH = 'ryu.lib.packet' +CLSNAME_ALIASES = { + ('ryu.lib.packet.ipv6', 'option'): 'ipv6option', + ('ryu.lib.packet.icmpv6', 'echo'): 'icmpv6echo', + ('ryu.lib.packet.bgp', 'StreamParser'): '', + ('ryu.lib.packet.bgp', 'StringifyMixin'): '', + ('ryu.lib.packet.dhcp', 'option'): 'dhcpoption', + ('ryu.lib.packet.dhcp', 'options'): 'dhcpoptions', + ('ryu.lib.packet.ospf', 'StringifyMixin'): '' +} + for modname, moddef in sys.modules.items(): if not modname.startswith(PKT_LIB_PATH) or not moddef: continue for (clsname, clsdef, ) in inspect.getmembers(moddef): if not inspect.isclass(clsdef): continue - exec('from %s import %s' % (modname, clsname)) + clsname_alias = CLSNAME_ALIASES.get((modname, clsname)) + if clsname_alias == '': + continue + elif clsname_alias is not None: + exec('from %s import %s as %s' % (modname, clsname, clsname_alias)) + else: + assert clsname not in globals(), ( + "%s.%s already defined" % (modname, clsname)) + exec('from %s import %s' % (modname, clsname)) """ Required test network: diff --git a/ryu/tests/test_lib.py b/ryu/tests/test_lib.py index 380297bf..344c30a2 100644 --- a/ryu/tests/test_lib.py +++ b/ryu/tests/test_lib.py @@ -267,6 +267,8 @@ def add_method(cls, method_name, method): method.__name__ = method_name if six.PY3: methodtype = types.MethodType(method, cls) + if not hasattr(method, "__qualname__"): + method.__qualname__ = "%s.%s" % (cls.__qualname__, method_name) else: methodtype = types.MethodType(method, None, cls) setattr(cls, method_name, methodtype) diff --git a/ryu/tests/unit/controller/cert.crt b/ryu/tests/unit/controller/cert.crt new file mode 100644 index 00000000..e1b2afc4 --- /dev/null +++ b/ryu/tests/unit/controller/cert.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDaDCCAlCgAwIBAgIJAKL09YuU92JPMA0GCSqGSIb3DQEBCwUAMEgxCzAJBgNV +BAYTAkpQMRMwEQYDVQQIDApTb21lLVN0YXRlMSQwIgYDVQQKDBtSeXUgU0ROIEZy +YW1ld29yayBDb21tdW5pdHkwIBcNMTkwMzI1MDE1NzQzWhgPMjI5MzAxMDYwMTU3 +NDNaMEgxCzAJBgNVBAYTAkpQMRMwEQYDVQQIDApTb21lLVN0YXRlMSQwIgYDVQQK +DBtSeXUgU0ROIEZyYW1ld29yayBDb21tdW5pdHkwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQDLT29+6JwD75wH7gPVxU52hrysBfxE6WjyT/nT+aSIQmZu +SU6/5hECOnV4YdyB7rxFu2WO2SD5PgeoHPBpTqtxrdTWoVOWVljnNcqEwSCS7bl9 +nbgX8uxCacg9qbFNJJRBAS0XQ2bSsD0GoOnhj3Olrz1u0wRIUqrR3A5giMbYwQPr +S4cmkxfgp2uV+WCHk40WxZnGgWzIRhO11GK9CAGncncPYhj+23w+GFaHIf00TdV2 +JEvwLFuLf1EaewZ7rz8zf1sLHAxqx20A6VdledEpNAzt1L8goPhk1mHvRgUC7E2v +FnSt1ePCJsVrvccudMdPBXSMfgJC2gmfdQefdSXRAgMBAAGjUzBRMB0GA1UdDgQW +BBRjlXSQ2rVjwOr1io6iJyidmjCNfzAfBgNVHSMEGDAWgBRjlXSQ2rVjwOr1io6i +JyidmjCNfzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCC1Uvo +4PdC5YQSXkAhrxgVhexp87VVkoWwpno75hvfoCjtSkb7+cskvQbPM14zbjIUrsli +qmTkjXyTUe8q5U06OitMAyM6qUvS0nFDi5aPQYV6N0XmJ+rV18prfQORyHvEmEyv +nqHVPoQkmGPpJ8aOVrTlECyxG7wLI2UxBEB3Atk51QHzbGGLKW7g5tHY6J5cMe/9 +ydeClJk2/AXkoqWkbtJrbw46alH97CajuLn/4D9B/Rm+M1Kg48gze5zJ7+WrB0Jl +pAhRqMM3upaOlXdeYDdNDgE0j/ulZGY2UssFIoHylcrb4QKQXjwqRXYhuuucJQJ3 +vsY4y1D/qps9llRL +-----END CERTIFICATE----- diff --git a/ryu/tests/unit/controller/cert.key b/ryu/tests/unit/controller/cert.key new file mode 100644 index 00000000..2b7f5f06 --- /dev/null +++ b/ryu/tests/unit/controller/cert.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQDLT29+6JwD75wH +7gPVxU52hrysBfxE6WjyT/nT+aSIQmZuSU6/5hECOnV4YdyB7rxFu2WO2SD5Pgeo +HPBpTqtxrdTWoVOWVljnNcqEwSCS7bl9nbgX8uxCacg9qbFNJJRBAS0XQ2bSsD0G +oOnhj3Olrz1u0wRIUqrR3A5giMbYwQPrS4cmkxfgp2uV+WCHk40WxZnGgWzIRhO1 +1GK9CAGncncPYhj+23w+GFaHIf00TdV2JEvwLFuLf1EaewZ7rz8zf1sLHAxqx20A +6VdledEpNAzt1L8goPhk1mHvRgUC7E2vFnSt1ePCJsVrvccudMdPBXSMfgJC2gmf +dQefdSXRAgMBAAECggEAcvPsB6Z/qB4Pa9Bg7LqNnaia/uy3cUND6lXb3MW3CK/6 +eHsMgqYTkd3502IJqpGQdCD70CPmZ+Zxr9UE/ZXUjAcMY3p952/U/o3EfwEvaMPu +8B6AG1Jn0Tk8VdkffY2kIYkHtLKQbanmJ1xOQRG6AsEti/7V2gqbuOKiYmSTgbPG +Upw9JNdtR6bZrGrrEXJbPCrSCej47MDyE+nt4zMIsqmY5IlbTMHcTKVDGeKbT9qT +7/Uyg+Tb62eber9iQhE0OteLt2GwrJR5yZ5QKNKM4SPqwYlOvQ9z289eZMVU3uwI +1NI1YRM5EMsdWrzFye7H/T/jsCaWrO0zmI/I4BMfEQKBgQDtUgPyY4PgVXVZ/hha +l5pi66GQ79+6LJP3SHb3I6p0iULq3oV+onG0Ezvx2vc21sbuLEazNlJoXzEzSIVM +/RjNJ9FsD/ENEuJedkspwtZZ4O4ZH6wKyHg/LCUly59ER37Ql/XwIX7adKCn7Z4d +9xN3aQmPtLna/aIZ8HyptRpT9QKBgQDbUB67YXiIFY+k5cwtK0m8T3rY4WNpEwzr +Y/1l+0EvXqCousU9MnLveyY8EcLDh5SnM0CvH4mFS8xL/r/kcUO9cHwuM+KZ77KN +Ukp9CRT9raxDZY/F0FVuET4LrJNnekCMsOnMxO51il/AHcul7886sEirkB1dsXND +nkh9h8g87QJ/cRikyN6j+kS/qCNvd7zH1lx0op2uAQs9eJsQFrbohKDlQwjIlZDU +nvyLlLbFGV1BcD+pcb5xh0vWJppo7EexihNvug/e0FwvhNTa/QvdGvgWf+KYGotu +wqxHB7wCKofn54CDs+xCh9kMtvqGX8FfhYiJBfMan0I//hydTEMCSQKBgEiv6E+g +gYtQ4hf8FczOsRSZnxSstv8HUlvd+wlG2hbyHPtvU5nx04gt38E+/bdCg3FbGlAw +eqrUMXTqjP0Q0SvDUVUa2zq76AjQwmFoli1x10tLKPieEQJ28oJ6Ayzjpus6Y3L7 +vjD02MFa3rkznxJLhPpfvGvmOVaq6km4rBQNAoGBALQGfaRiAtp6lSubi4Etdwtg +Tps2o1SBXfzENpq6s99k+UdCBLh90uzuA897GClsUYeuAYUyxQP3otIZUuSjq/Ht +JHYwT9QxOkSYrNCfQW/nF0CJjZ6TcvcFp8SdyUUbwCR2rkDK7LlMzxkfU3cCrwMP +q51oIVlKjIxg86JJXrRQ +-----END PRIVATE KEY----- diff --git a/ryu/tests/unit/controller/test_controller.py b/ryu/tests/unit/controller/test_controller.py index a94e7b43..ce09ac7e 100644 --- a/ryu/tests/unit/controller/test_controller.py +++ b/ryu/tests/unit/controller/test_controller.py @@ -22,6 +22,7 @@ except ImportError: import json import os +import ssl import sys import warnings import logging @@ -33,9 +34,11 @@ from nose.tools import eq_, raises from ryu.base import app_manager # To suppress cyclic import from ryu.controller import controller from ryu.controller import handler +from ryu.lib import hub from ryu.ofproto import ofproto_v1_3_parser from ryu.ofproto import ofproto_v1_2_parser from ryu.ofproto import ofproto_v1_0_parser +hub.patch() LOG = logging.getLogger('test_controller') @@ -177,3 +180,53 @@ class Test_Datapath(unittest.TestCase): self.assertEqual(state, handler.MAIN_DISPATCHER) self.assertEqual(kwargs, {}) self.assertEqual(expected_json, output_json) + + +class TestOpenFlowController(unittest.TestCase): + """ + Test cases for OpenFlowController + """ + @mock.patch("ryu.controller.controller.CONF") + def _test_ssl(self, this_dir, port, conf_mock): + conf_mock.ofp_ssl_listen_port = port + conf_mock.ofp_listen_host = "127.0.0.1" + conf_mock.ca_certs = None + conf_mock.ciphers = None + conf_mock.ctl_cert = os.path.join(this_dir, 'cert.crt') + conf_mock.ctl_privkey = os.path.join(this_dir, 'cert.key') + c = controller.OpenFlowController() + c() + + def test_ssl(self): + """Tests SSL server functionality.""" + # TODO: TLS version enforcement is necessary to avoid + # vulnerable versions. Currently, this only tests TLS + # connectivity. + this_dir = os.path.dirname(sys.modules[__name__].__file__) + saved_exception = None + try: + ssl_version = ssl.PROTOCOL_TLS + except AttributeError: + # For compatibility with older pythons. + ssl_version = ssl.PROTOCOL_TLSv1 + for i in range(3): + try: + # Try a few times as this can fail with EADDRINUSE + port = random.randint(5000, 10000) + server = hub.spawn(self._test_ssl, this_dir, port) + hub.sleep(1) + client = hub.StreamClient(("127.0.0.1", port), + timeout=5, + ssl_version=ssl_version) + if client.connect() is not None: + break + except Exception as e: + saved_exception = e + continue + finally: + try: + hub.kill(server) + except Exception: + pass + else: + self.fail("Failed to connect: " + str(saved_exception)) diff --git a/ryu/tests/unit/lib/ovs/test_vsctl.py b/ryu/tests/unit/lib/ovs/test_vsctl.py index 84698eec..92e00f62 100644 --- a/ryu/tests/unit/lib/ovs/test_vsctl.py +++ b/ryu/tests/unit/lib/ovs/test_vsctl.py @@ -35,7 +35,7 @@ LOG = logging.getLogger(__name__) DOCKER_IMAGE_MININET = 'osrg/ryu-book' OVSDB_MANAGER_ADDR = 'ptcp:6640' -OVSDB_SWITCH_ADDR = 'tcp:%s:6640' +OVSDB_SWITCH_ADDR = 'tcp:0.0.0.0:6640' def setUpModule(): @@ -93,7 +93,7 @@ class TestVSCtl(unittest.TestCase): @classmethod def _docker_run(cls, image): - return _run('docker run --privileged -t -d %s' % image)[0] + return _run('docker run --privileged -t -d -p 6640:6640 %s' % image)[0] @classmethod def _docker_stop(cls, container): @@ -124,7 +124,7 @@ class TestVSCtl(unittest.TestCase): @classmethod def _set_up_vsctl(cls): - cls.vsctl = vsctl.VSCtl(OVSDB_SWITCH_ADDR % cls.container_mn_ip) + cls.vsctl = vsctl.VSCtl(OVSDB_SWITCH_ADDR) @classmethod def setUpClass(cls): diff --git a/ryu/tests/unit/lib/test_mrtlib.py b/ryu/tests/unit/lib/test_mrtlib.py index e870f401..55c7cda0 100644 --- a/ryu/tests/unit/lib/test_mrtlib.py +++ b/ryu/tests/unit/lib/test_mrtlib.py @@ -19,6 +19,7 @@ import bz2 import io import logging import os +import struct import sys import unittest @@ -609,6 +610,66 @@ class TestMrtlibMrtPeer(unittest.TestCase): eq_(buf, output) +class TestMrtlibMrtRibEntry(unittest.TestCase): + """ + Test case for ryu.lib.mrtlib.MrtRibEntry. + """ + + def test_parse_add_path(self): + peer_index = 1 + originated_time = 2 + nexthop = '1.1.1.1' + bgp_attribute = bgp.BGPPathAttributeNextHop(nexthop) + path_id = 3 + bgp_attr_buf = bgp_attribute.serialize() + attr_len = len(bgp_attr_buf) + buf = ( + b'\x00\x01' # peer_index + b'\x00\x00\x00\x02' # originated_time + b'\x00\x00\x00\x03' # path_id + + struct.pack('!H', attr_len) # attr_len + + bgp_attribute.serialize() # bgp_attributes + ) + + rib, rest = mrtlib.MrtRibEntry.parse(buf, is_addpath=True) + + eq_(peer_index, rib.peer_index) + eq_(originated_time, rib.originated_time) + eq_(path_id, rib.path_id) + eq_(attr_len, rib.attr_len) + eq_(1, len(rib.bgp_attributes)) + eq_(nexthop, rib.bgp_attributes[0].value) + eq_(b'', rest) + + def test_serialize_add_path(self): + peer_index = 1 + originated_time = 2 + nexthop = '1.1.1.1' + bgp_attribute = bgp.BGPPathAttributeNextHop(nexthop) + path_id = 3 + bgp_attr_buf = bgp_attribute.serialize() + attr_len = len(bgp_attr_buf) + buf = ( + b'\x00\x01' # peer_index + b'\x00\x00\x00\x02' # originated_time + b'\x00\x00\x00\x03' # path_id + + struct.pack('!H', attr_len) # attr_len + + bgp_attribute.serialize() # bgp_attributes + ) + + rib = mrtlib.MrtRibEntry( + peer_index=peer_index, + originated_time=originated_time, + bgp_attributes=[bgp_attribute], + # attr_len=attr_len, + path_id=path_id, + ) + + output = rib.serialize() + + eq_(buf, output) + + class TestMrtlibBgp4MpMrtRecord(unittest.TestCase): """ Test case for ryu.lib.mrtlib.Bgp4MpMrtRecord. diff --git a/ryu/tests/unit/lib/test_ofctl_action_match.py b/ryu/tests/unit/lib/test_ofctl_action_match.py index 11e27f78..9e9f2e46 100644 --- a/ryu/tests/unit/lib/test_ofctl_action_match.py +++ b/ryu/tests/unit/lib/test_ofctl_action_match.py @@ -413,7 +413,7 @@ class Test_ofctl(unittest.TestCase): # without mask eq_(eth, field_value) return - elif key in['nw_src', 'nw_dst', 'arp_spa', 'arp_tpa']: + elif key in ['nw_src', 'nw_dst', 'arp_spa', 'arp_tpa']: # IPv4 address if test.ver == ofproto_v1_0.OFP_VERSION: ipv4, mask = _to_match_ip(value) diff --git a/ryu/tests/unit/lib/test_rpc.py b/ryu/tests/unit/lib/test_rpc.py index 2df123ee..4fba5068 100644 --- a/ryu/tests/unit/lib/test_rpc.py +++ b/ryu/tests/unit/lib/test_rpc.py @@ -138,13 +138,18 @@ class Test_rpc(unittest.TestCase): assert result == obj assert isinstance(result, numbers.Integral) - @raises(TypeError) def test_0_call_bytearray(self): c = rpc.Client(self._client_sock) obj = bytearray(b'foo') - result = c.call('resp', [obj]) - assert result == obj - assert isinstance(result, str) + # Note: msgpack-python version 0.50 or later supports bytearray + # objects, here ignores TypeError for the backward compatibility. + try: + result = c.call('resp', [obj]) + except TypeError: + # Case with msgpack-python version 0.4.x or earlier. + return + self.assertEqual(obj, result) + self.assertIsInstance(result, six.binary_type) def test_1_shutdown_wr(self): # test if the server shutdown on disconnect diff --git a/ryu/tests/unit/ofproto/json/of13/ovs-ofctl-of13-action_ct_clear.packet.json b/ryu/tests/unit/ofproto/json/of13/ovs-ofctl-of13-action_ct_clear.packet.json new file mode 100644 index 00000000..32b88b72 --- /dev/null +++ b/ryu/tests/unit/ofproto/json/of13/ovs-ofctl-of13-action_ct_clear.packet.json @@ -0,0 +1,55 @@ +{ + "OFPFlowMod": { + "buffer_id": 4294967295, + "command": 0, + "cookie": 0, + "cookie_mask": 0, + "flags": 0, + "hard_timeout": 0, + "idle_timeout": 0, + "instructions": [ + { + "OFPInstructionActions": { + "actions": [ + { + "NXActionCTClear": { + "experimenter": 8992, + "len": 16, + "subtype": 43, + "type": 65535 + } + } + ], + "len": 24, + "type": 4 + } + } + ], + "match": { + "OFPMatch": { + "length": 22, + "oxm_fields": [ + { + "OXMTlv": { + "field": "eth_type", + "mask": null, + "value": 2048 + } + }, + { + "OXMTlv": { + "field": "ct_state", + "mask": 32, + "value": 32 + } + } + ], + "type": 1 + } + }, + "out_group": 4294967295, + "out_port": 4294967295, + "priority": 32768, + "table_id": 3 + } +} diff --git a/ryu/tests/unit/packet/test_bmp.py b/ryu/tests/unit/packet/test_bmp.py index f93b8014..d0bffecf 100644 --- a/ryu/tests/unit/packet/test_bmp.py +++ b/ryu/tests/unit/packet/test_bmp.py @@ -54,12 +54,31 @@ class Test_bmp(unittest.TestCase): eq_(msg.to_jsondict(), msg2.to_jsondict()) eq_(rest, b'') + def test_route_monitoring_adj_rib_out(self): + update = bgp.BGPUpdate() + msg = bmp.BMPRouteMonitoring(bgp_update=update, + peer_type=bmp.BMP_PEER_TYPE_GLOBAL, + is_post_policy=True, + is_adj_rib_out=True, + peer_distinguisher=0, + peer_address='192.0.2.1', + peer_as=30000, + peer_bgp_id='192.0.2.1', + timestamp=self._time()) + binmsg = msg.serialize() + msg2, rest = bmp.BMPMessage.parser(binmsg) + eq_(msg.to_jsondict(), msg2.to_jsondict()) + eq_(rest, b'') + def test_statistics_report(self): stats = [{'type': bmp.BMP_STAT_TYPE_REJECTED, 'value': 100}, {'type': bmp.BMP_STAT_TYPE_DUPLICATE_PREFIX, 'value': 200}, {'type': bmp.BMP_STAT_TYPE_DUPLICATE_WITHDRAW, 'value': 300}, {'type': bmp.BMP_STAT_TYPE_ADJ_RIB_IN, 'value': 100000}, - {'type': bmp.BMP_STAT_TYPE_LOC_RIB, 'value': 500000}] + {'type': bmp.BMP_STAT_TYPE_LOC_RIB, 'value': 500000}, + {'type': bmp.BMP_STAT_TYPE_ADJ_RIB_OUT, 'value': 95000}, + {'type': bmp.BMP_STAT_TYPE_EXPORT_RIB, 'value': 50000}, + {'type': bmp.BMP_STAT_TYPE_EXPORT_RIB, 'value': 50000}] msg = bmp.BMPStatisticsReport(stats=stats, peer_type=bmp.BMP_PEER_TYPE_GLOBAL, is_post_policy=True, diff --git a/ryu/tests/unit/packet/test_lldp.py b/ryu/tests/unit/packet/test_lldp.py index d8d261c2..35c4f58e 100644 --- a/ryu/tests/unit/packet/test_lldp.py +++ b/ryu/tests/unit/packet/test_lldp.py @@ -227,8 +227,7 @@ class TestLLDPOptionalTLV(unittest.TestCase): + b'\x73\x74\x65\x72\x20\x30\x35\x2f' \ + b'\x32\x37\x2f\x30\x35\x20\x30\x34' \ + b'\x3a\x35\x33\x3a\x31\x31\x00\x0e' \ - + b'\x05\x01\x00\x14\x00\x14\x10\x0e' \ - + b'\x07' \ + + b'\x04\x00\x14\x00\x14\x10\x0e\x07' \ + b'\x06\x00\x01\x30\xf9\xad\xa0\x02' \ + b'\x00\x00\x03\xe9\x00\xfe\x07\x00' \ + b'\x12\x0f\x02\x07\x01\x00\xfe\x09' \ @@ -274,7 +273,6 @@ class TestLLDPOptionalTLV(unittest.TestCase): # SystemCapabilities eq_(tlvs[6].tlv_type, lldp.LLDP_TLV_SYSTEM_CAPABILITIES) - eq_(tlvs[6].subtype, lldp.ChassisID.SUB_CHASSIS_COMPONENT) eq_(tlvs[6].system_cap & lldp.SystemCapabilities.CAP_MAC_BRIDGE, lldp.SystemCapabilities.CAP_MAC_BRIDGE) eq_(tlvs[6].enabled_cap & lldp.SystemCapabilities.CAP_MAC_BRIDGE, @@ -322,7 +320,6 @@ class TestLLDPOptionalTLV(unittest.TestCase): system_description=b'Summit300-48 - Version 7.4e.1 (Build 5) ' + b'by Release_Master 05/27/05 04:53:11\x00') tlv_system_capabilities = lldp.SystemCapabilities( - subtype=lldp.ChassisID.SUB_CHASSIS_COMPONENT, system_cap=0x14, enabled_cap=0x14) tlv_management_address = lldp.ManagementAddress( @@ -360,7 +357,6 @@ class TestLLDPOptionalTLV(unittest.TestCase): system_description=b'Summit300-48 - Version 7.4e.1 (Build 5) ' + b'by Release_Master 05/27/05 04:53:11\x00') sys_cap = lldp.SystemCapabilities( - subtype=lldp.ChassisID.SUB_CHASSIS_COMPONENT, system_cap=0x14, enabled_cap=0x14) man_addr = lldp.ManagementAddress( @@ -434,8 +430,7 @@ class TestLLDPOptionalTLV(unittest.TestCase): _sys_desc_str) # SystemCapabilities string - sys_cap_values = {'subtype': lldp.ChassisID.SUB_CHASSIS_COMPONENT, - 'system_cap': 0x14, + sys_cap_values = {'system_cap': 0x14, 'enabled_cap': 0x14, 'len': sys_cap.len, 'typelen': sys_cap.typelen} @@ -515,7 +510,6 @@ class TestLLDPOptionalTLV(unittest.TestCase): system_description=b'Summit300-48 - Version 7.4e.1 (Build 5) ' + b'by Release_Master 05/27/05 04:53:11\x00') sys_cap = lldp.SystemCapabilities( - subtype=lldp.ChassisID.SUB_CHASSIS_COMPONENT, system_cap=0x14, enabled_cap=0x14) man_addr = lldp.ManagementAddress( diff --git a/ryu/tests/unit/test_requirements.py b/ryu/tests/unit/test_requirements.py deleted file mode 100644 index 9f50a518..00000000 --- a/ryu/tests/unit/test_requirements.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import logging -import os -import sys -import unittest - -import pkg_resources -from pip.req import parse_requirements -from pip.download import PipSession -from six.moves import urllib - -from nose.tools import ok_ - - -LOG = logging.getLogger(__name__) - -MOD_DIR = os.path.dirname(sys.modules[__name__].__file__) -_RYU_REQUIREMENTS_FILES = [ - '../../../tools/pip-requires', - '../../../tools/optional-requires', -] -RYU_REQUIREMENTS_FILES = [ - os.path.join(MOD_DIR, f) for f in _RYU_REQUIREMENTS_FILES] - -OPENSTACK_REQUIREMENTS_REPO = 'https://github.com/openstack/requirements' -OPENSTACK_REQUIREMENTS_URL = ( - 'https://github.com/openstack/requirements/raw/master/') -_OPENSTACK_REQUIREMENTS_FILES = [ - 'requirements.txt', - 'global-requirements.txt', -] -OPENSTACK_REQUIREMENTS_FILES = [ - urllib.parse.urljoin(OPENSTACK_REQUIREMENTS_URL, f) - for f in _OPENSTACK_REQUIREMENTS_FILES] - - -def _get_requirements(files): - requirements = {} - for f in files: - req = parse_requirements(f, session=PipSession()) - for r in req: - requirements[r.name] = str(r.req) - - return requirements - - -OPENSTACK_REQUIREMENTS = _get_requirements(OPENSTACK_REQUIREMENTS_FILES) -RYU_REQUIREMENTS = _get_requirements(RYU_REQUIREMENTS_FILES) - - -class TestRequirements(unittest.TestCase): - """ - Test whether the requirements of Ryu has no conflict with that - of other projects. - """ - - def setUp(self): - pass - - def tearDown(self): - pass - - def test_with_openstack_requirements(self): - try: - for name, req in OPENSTACK_REQUIREMENTS.items(): - if name in RYU_REQUIREMENTS: - ok_(pkg_resources.require(req)) - except pkg_resources.VersionConflict as e: - LOG.exception( - 'Some requirements of Ryu are conflicting with that of ' - 'OpenStack project: %s' % OPENSTACK_REQUIREMENTS_REPO) - raise e diff --git a/ryu/utils.py b/ryu/utils.py index 8bfdf7da..ca14c12c 100644 --- a/ryu/utils.py +++ b/ryu/utils.py @@ -126,34 +126,3 @@ def binary_str(data): """ # convert data into bytearray explicitly return ''.join('\\x%02x' % byte for byte in bytearray(data)) - - -def parse_requirements(requirements_files=None): - """ - Parses requirements files and returns a list of requirements. - - Returned list would be like:: - - ['foo', 'bar>=X.X', ...] - - :param requirements_files: List of requirements files. The default - is ['requirements.txt', 'tools/pip-requires']. - :return: List of requirements. - """ - from pip import req as pip_req - from pip.download import PipSession - - requirements_files = requirements_files or [ - 'requirements.txt', - 'tools/pip-requires', - ] - - requirements = [] - for f in requirements_files: - if not os.path.isfile(f): - continue - - for r in pip_req.parse_requirements(f, session=PipSession()): - requirements.append(str(r.req)) - - return requirements diff --git a/setup.cfg b/setup.cfg index 22737a31..b3716c1c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,7 +4,7 @@ summary = Component-based Software-defined Networking Framework license = Apache License 2.0 author = Ryu project team author-email = ryu-devel@lists.sourceforge.net -home-page = http://osrg.github.io/ryu/ +home-page = https://ryu-sdn.org description-file = README.rst platform = any classifier = @@ -13,9 +13,12 @@ classifier = Topic :: System :: Networking Natural Language :: English Programming Language :: Python - Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 - Programming Language :: Python :: 3.4 + Programming Language :: Python :: 3.5 + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 Operating System :: Unix keywords = openflow diff --git a/setup.py b/setup.py index cf2a404d..fee79eb1 100644 --- a/setup.py +++ b/setup.py @@ -14,12 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# a bug workaround. http://bugs.python.org/issue15881 -try: - import multiprocessing -except ImportError: - pass - import setuptools import ryu.hooks diff --git a/tools/install_venv.py b/tools/install_venv.py index 29639801..13a5bc17 100644 --- a/tools/install_venv.py +++ b/tools/install_venv.py @@ -70,29 +70,29 @@ def check_dependencies(): if not HAS_VIRTUALENV: raise Exception('Virtualenv not found. ' + \ 'Try installing python-virtualenv') - print 'done.' + print('done.') # pylint: disable=print-statement def create_virtualenv(venv=VENV, install_pip=False): """Creates the virtual environment and installs PIP only into the virtual environment """ - print 'Creating venv...', + print('Creating venv...') # pylint: disable=print-statement install = ['virtualenv', '-q', venv] run_command(install) - print 'done.' - print 'Installing pip in virtualenv...', + print('done.') # pylint: disable=print-statement + print('Installing pip in virtualenv...') # pylint: disable=print-statement if install_pip and \ not run_command(['tools/with_venv.sh', 'easy_install', 'pip>1.0']): die("Failed to install pip.") - print 'done.' + print('done.') # pylint: disable=print-statement def install_dependencies(venv=VENV): - print 'Installing dependencies with pip (this can take a while)...' + print('Installing dependencies with pip (this can take a while)...') # pylint: disable=print-statement run_command(['tools/with_venv.sh', 'pip', 'install', '-r', PIP_REQUIRES], redirect_output=False) run_command(['tools/with_venv.sh', 'pip', 'install', '-r', @@ -126,7 +126,7 @@ def print_help(): Also, make test will automatically use the virtualenv. """ - print help + print(help) # pylint: disable=print-statement def main(argv): diff --git a/tools/pip-requires b/tools/pip-requires index ef475c0a..b2ecef8a 100644 --- a/tools/pip-requires +++ b/tools/pip-requires @@ -1,12 +1,12 @@ -# NOTE: OpenStack avoids the newer versions of eventlet, because of the +# NOTE: OpenStack avoids some versions of eventlet, because of the # following issue. # https://github.com/eventlet/eventlet/issues/401 -eventlet!=0.18.3,>=0.18.2,!=0.20.1,<0.21.0 -msgpack-python>=0.3.0 # RPC library, BGP speaker(net_cntl) +eventlet==0.30.0 +msgpack>=0.4.0 # RPC library, BGP speaker(net_cntl) netaddr -oslo.config>=1.15.0 +oslo.config>=2.5.0 ovs>=2.6.0 # OVSDB routes # wsgi six>=1.4.0 -tinyrpc # RPC library, BGP speaker(net_cntl) +tinyrpc==0.9.4 # RPC library, BGP speaker(net_cntl) webob>=1.2 # wsgi diff --git a/tox.ini b/tox.ini index 758d1661..37b95397 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,13 @@ [tox] -envlist = py27,py34,py35,pypy26,pycodestyle,autopep8 +envlist = py35,py36,py37,py38,py39,pypy,pycodestyle,autopep8 + +[gh-actions] +python = + 3.5: py35 + 3.6: py36, pycodestyle, autopep8 + 3.7: py37 + 3.8: py38 + 3.9: py39 [testenv] deps = @@ -20,12 +28,7 @@ commands = commands = python ryu/tests/integrated/run_test.py -[testenv:py27] -commands = - {[testenv]commands} - {[testenv:scenario]commands} - -[testenv:py34] +[testenv:py36] commands = {[testenv]commands} {[testenv:scenario]commands} @@ -52,14 +55,15 @@ commands = [pycodestyle] exclude = pbr-*,.venv,.tox,.git,doc,dist,tools,vcsversion.py,.pyc,ryu/contrib -# W503: line break occurred before a binary operator +# W503: line break before binary operator +# W504: line break after binary operator # E116: unexpected indentation (comment) # E402: module level import not at top of file # E501: line too long (>79 characters) # E722: do not use bare except, specify exception instead # E731: do not assign a lambda expression, use a def # E741: do not use variables named 'l', 'O', or 'I' -ignore = W503,E116,E402,E501,E722,E731,E741 +ignore = W503,W504,E116,E402,E501,E722,E731,E741 [pep8] exclude = pbr-*,.venv,.tox,.git,doc,dist,tools,vcsversion.py,.pyc,ryu/contrib