mirror of
https://github.com/faucetsdn/ryu.git
synced 2026-01-22 09:01:22 +01:00
Merge branch 'master' into point-to-multipoint
This commit is contained in:
commit
f3d8c366db
25
.github/workflows/tests-unit.yml
vendored
Normal file
25
.github/workflows/tests-unit.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: Unit tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
unit-tests:
|
||||
name: Unit tests
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.5, 3.6, 3.7, 3.8, 3.9]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade -r pip-requirements.txt
|
||||
pip install tox tox-gh-actions coveralls
|
||||
bash ryu/tests/integrated/common/install_docker_test_pkg_for_github_actions.sh
|
||||
- name: Test with tox
|
||||
run: NOSE_VERBOSE=0 tox
|
||||
15
.renovaterc.json
Normal file
15
.renovaterc.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"separateMajorMinor": false,
|
||||
"schedule": [
|
||||
"after 10pm every weekday",
|
||||
"before 5am every weekday",
|
||||
"every weekend"
|
||||
],
|
||||
"timezone": "Pacific/Auckland",
|
||||
"extends": [
|
||||
"config:base",
|
||||
":prHourlyLimit1",
|
||||
":preserveSemverRanges",
|
||||
"docker:enableMajor"
|
||||
]
|
||||
}
|
||||
9
.stickler.yml
Normal file
9
.stickler.yml
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
linters:
|
||||
flake8:
|
||||
python: 3
|
||||
max-line-length: 120
|
||||
pep8:
|
||||
python: 3
|
||||
max-line-length: 120
|
||||
py3k:
|
||||
40
.travis.yml
40
.travis.yml
@ -1,40 +0,0 @@
|
||||
language: python
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- python: 3.6
|
||||
env: TOX_ENV=pycodestyle
|
||||
- python: 3.6
|
||||
env: TOX_ENV=py36
|
||||
- python: 3.6
|
||||
env: TOX_ENV=autopep8
|
||||
|
||||
- python: 2.7
|
||||
env: TOX_ENV=pycodestyle
|
||||
- python: 2.7
|
||||
env: TOX_ENV=py27
|
||||
|
||||
- python: 3.5
|
||||
env: TOX_ENV=py35
|
||||
|
||||
- python: 3.7-dev
|
||||
env: TOX_ENV=py37
|
||||
|
||||
# This is disabled because of trouble running on travis CI.
|
||||
# - python: pypy
|
||||
# env: TOX_ENV=pypy
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
sudo: required # Required to enable Docker service
|
||||
|
||||
install:
|
||||
- pip install tox coveralls
|
||||
- bash ryu/tests/integrated/common/install_docker_test_pkg_for_travis.sh
|
||||
|
||||
script:
|
||||
- NOSE_VERBOSE=0 tox -e $TOX_ENV
|
||||
|
||||
after_success:
|
||||
- coveralls
|
||||
@ -30,9 +30,9 @@ features (it's not a must though).
|
||||
|
||||
Python version and libraries
|
||||
============================
|
||||
* Python 2.7, 3.5, 3.6, 3.7:
|
||||
* Python 3.5, 3.6, 3.7, 3.8, 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:
|
||||
|
||||
4
debian/control
vendored
4
debian/control
vendored
@ -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,
|
||||
@ -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,
|
||||
|
||||
@ -67,11 +67,16 @@ the ports.
|
||||
dp = msg.datapath
|
||||
ofp = dp.ofproto
|
||||
ofp_parser = dp.ofproto_parser
|
||||
|
||||
|
||||
actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD)]
|
||||
|
||||
data = None
|
||||
if msg.buffer_id == ofp.OFP_NO_BUFFER:
|
||||
data = msg.data
|
||||
|
||||
out = ofp_parser.OFPPacketOut(
|
||||
datapath=dp, buffer_id=msg.buffer_id, in_port=msg.in_port,
|
||||
actions=actions)
|
||||
actions=actions, data = data)
|
||||
dp.send_msg(out)
|
||||
|
||||
|
||||
|
||||
1
pip-requirements.txt
Normal file
1
pip-requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
pip==20.3.4
|
||||
@ -108,8 +108,15 @@ class WebSocketRegistrationWrapper(object):
|
||||
|
||||
class _AlreadyHandledResponse(Response):
|
||||
# XXX: Eventlet API should not be used directly.
|
||||
from eventlet.wsgi import ALREADY_HANDLED
|
||||
_ALREADY_HANDLED = ALREADY_HANDLED
|
||||
# https://github.com/benoitc/gunicorn/pull/2581
|
||||
from packaging import version
|
||||
import eventlet
|
||||
if version.parse(eventlet.__version__) >= version.parse("0.30.3"):
|
||||
import eventlet.wsgi
|
||||
_ALREADY_HANDLED = getattr(eventlet.wsgi, "ALREADY_HANDLED", None)
|
||||
else:
|
||||
from eventlet.wsgi import ALREADY_HANDLED
|
||||
_ALREADY_HANDLED = ALREADY_HANDLED
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
return self._ALREADY_HANDLED
|
||||
|
||||
@ -67,6 +67,7 @@ CONF.register_cli_opts([
|
||||
cfg.StrOpt('ctl-privkey', default=None, help='controller private key'),
|
||||
cfg.StrOpt('ctl-cert', default=None, help='controller certificate'),
|
||||
cfg.StrOpt('ca-certs', default=None, help='CA certificates'),
|
||||
cfg.StrOpt('ciphers', default=None, help='list of ciphers to enable'),
|
||||
cfg.ListOpt('ofp-switch-address-list', item_type=str, default=[],
|
||||
help='list of IP address and port pairs (default empty). '
|
||||
'e.g., "127.0.0.1:6653,[::1]:6653"'),
|
||||
@ -182,6 +183,9 @@ class OpenFlowController(object):
|
||||
# Restrict non-safe versions
|
||||
ssl_args['ssl_ctx'].options |= ssl.OP_NO_SSLv3 | ssl.OP_NO_SSLv2
|
||||
|
||||
if CONF.ciphers is not None:
|
||||
ssl_args['ciphers'] = CONF.ciphers
|
||||
|
||||
if CONF.ca_certs is not None:
|
||||
server = StreamServer((CONF.ofp_listen_host,
|
||||
ofp_ssl_listen_port),
|
||||
@ -313,7 +317,8 @@ class Datapath(ofproto_protocol.ProtocolDesc):
|
||||
self.state = state
|
||||
ev = ofp_event.EventOFPStateChange(self)
|
||||
ev.state = state
|
||||
self.ofp_brick.send_event_to_observers(ev, state)
|
||||
if self.ofp_brick is not None:
|
||||
self.ofp_brick.send_event_to_observers(ev, state)
|
||||
|
||||
# Low level socket handling layer
|
||||
@_deactivate
|
||||
@ -358,16 +363,17 @@ class Datapath(ofproto_protocol.ProtocolDesc):
|
||||
# LOG.debug('queue msg %s cls %s', msg, msg.__class__)
|
||||
if msg:
|
||||
ev = ofp_event.ofp_msg_to_ev(msg)
|
||||
self.ofp_brick.send_event_to_observers(ev, self.state)
|
||||
if self.ofp_brick is not None:
|
||||
self.ofp_brick.send_event_to_observers(ev, self.state)
|
||||
|
||||
def dispatchers(x):
|
||||
return x.callers[ev.__class__].dispatchers
|
||||
def dispatchers(x):
|
||||
return x.callers[ev.__class__].dispatchers
|
||||
|
||||
handlers = [handler for handler in
|
||||
self.ofp_brick.get_handlers(ev) if
|
||||
self.state in dispatchers(handler)]
|
||||
for handler in handlers:
|
||||
handler(ev)
|
||||
handlers = [handler for handler in
|
||||
self.ofp_brick.get_handlers(ev) if
|
||||
self.state in dispatchers(handler)]
|
||||
for handler in handlers:
|
||||
handler(ev)
|
||||
|
||||
buf = buf[msg_len:]
|
||||
buf_len = len(buf)
|
||||
|
||||
@ -149,6 +149,7 @@ def register_service(service):
|
||||
there are applications consuming OFP events.
|
||||
"""
|
||||
frame = inspect.currentframe()
|
||||
m_name = frame.f_back.f_globals['__name__']
|
||||
m = sys.modules[m_name]
|
||||
m._SERVICE_NAME = service
|
||||
if frame is not None:
|
||||
m_name = frame.f_back.f_globals['__name__']
|
||||
m = sys.modules[m_name]
|
||||
m._SERVICE_NAME = service
|
||||
|
||||
@ -50,7 +50,7 @@ class MacToPortTable(object):
|
||||
return self.mac_to_port[dpid].get(mac)
|
||||
|
||||
def mac_list(self, dpid, port):
|
||||
return [mac for (mac, port_) in self.mac_to_port.get(dpid).items()
|
||||
return [mac for (mac, port_) in self.mac_to_port.get(dpid, {}).items()
|
||||
if port_ == port]
|
||||
|
||||
def mac_del(self, dpid, mac):
|
||||
|
||||
@ -47,7 +47,7 @@ def register_switch_address(addr, interval=None):
|
||||
def _retry_loop():
|
||||
# Delays registration if ofp_handler is not started yet
|
||||
while True:
|
||||
if ofp_handler.controller is not None:
|
||||
if ofp_handler is not None and ofp_handler.controller is not None:
|
||||
for a, i in _TMP_ADDRESSES.items():
|
||||
ofp_handler.controller.spawn_client_loop(a, i)
|
||||
hub.sleep(1)
|
||||
@ -69,6 +69,6 @@ def unregister_switch_address(addr):
|
||||
"""
|
||||
ofp_handler = app_manager.lookup_service_brick(ofp_event.NAME)
|
||||
# Do nothing if ofp_handler is not started yet
|
||||
if ofp_handler.controller is None:
|
||||
if ofp_handler is None or ofp_handler.controller is None:
|
||||
return
|
||||
ofp_handler.controller.stop_client_loop(addr)
|
||||
|
||||
@ -127,21 +127,25 @@ if HUB_TYPE == 'eventlet':
|
||||
self.server = eventlet.listen(listen_info)
|
||||
|
||||
if ssl_args:
|
||||
def wrap_and_handle(sock, addr):
|
||||
ssl_args.setdefault('server_side', True)
|
||||
if 'ssl_ctx' in ssl_args:
|
||||
ctx = ssl_args.pop('ssl_ctx')
|
||||
ctx.load_cert_chain(ssl_args.pop('certfile'),
|
||||
ssl_args.pop('keyfile'))
|
||||
if 'cert_reqs' in ssl_args:
|
||||
ctx.verify_mode = ssl_args.pop('cert_reqs')
|
||||
if 'ca_certs' in ssl_args:
|
||||
ctx.load_verify_locations(ssl_args.pop('ca_certs'))
|
||||
ssl_args.setdefault('server_side', True)
|
||||
if 'ssl_ctx' in ssl_args:
|
||||
ctx = ssl_args.pop('ssl_ctx')
|
||||
ctx.load_cert_chain(ssl_args.pop('certfile'),
|
||||
ssl_args.pop('keyfile'))
|
||||
if 'cert_reqs' in ssl_args:
|
||||
ctx.verify_mode = ssl_args.pop('cert_reqs')
|
||||
if 'ca_certs' in ssl_args:
|
||||
ctx.load_verify_locations(ssl_args.pop('ca_certs'))
|
||||
|
||||
def wrap_and_handle_ctx(sock, addr):
|
||||
handle(ctx.wrap_socket(sock, **ssl_args), addr)
|
||||
else:
|
||||
|
||||
self.handle = wrap_and_handle_ctx
|
||||
else:
|
||||
def wrap_and_handle_ssl(sock, addr):
|
||||
handle(ssl.wrap_socket(sock, **ssl_args), addr)
|
||||
|
||||
self.handle = wrap_and_handle
|
||||
self.handle = wrap_and_handle_ssl
|
||||
else:
|
||||
self.handle = handle
|
||||
|
||||
|
||||
@ -114,7 +114,7 @@ class OVSBridge(object):
|
||||
"""
|
||||
|
||||
def __init__(self, CONF, datapath_id, ovsdb_addr, timeout=None,
|
||||
exception=None):
|
||||
exception=None, br_name=None):
|
||||
super(OVSBridge, self).__init__()
|
||||
self.datapath_id = datapath_id
|
||||
self.ovsdb_addr = ovsdb_addr
|
||||
@ -122,7 +122,7 @@ class OVSBridge(object):
|
||||
self.timeout = timeout or CONF.ovsdb_timeout
|
||||
self.exception = exception
|
||||
|
||||
self.br_name = None
|
||||
self.br_name = br_name
|
||||
|
||||
def run_command(self, commands):
|
||||
"""
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -788,7 +788,7 @@ def generate(ofp_name, ofpp_name):
|
||||
|
||||
Example::
|
||||
|
||||
actions += [parser.NXActionResubmit(in_port=8080,
|
||||
actions += [parser.NXActionResubmitTable(in_port=8080,
|
||||
table_id=10)]
|
||||
"""
|
||||
_subtype = nicira_ext.NXAST_RESUBMIT_TABLE
|
||||
|
||||
@ -1754,7 +1754,7 @@ class OFPMatchField(StringifyMixin):
|
||||
(value, mask) = struct.unpack_from(pack_str, buf, offset + 4)
|
||||
else:
|
||||
(value,) = struct.unpack_from(cls.pack_str, buf, offset + 4)
|
||||
return cls(header, value, mask)
|
||||
return cls(header, value, mask) # pytype: disable=wrong-arg-count
|
||||
|
||||
def serialize(self, buf, offset):
|
||||
if ofproto.oxm_tlv_header_extract_hasmask(self.header):
|
||||
@ -2773,8 +2773,9 @@ class OFPFlowMod(MsgBase):
|
||||
try:
|
||||
while offset < msg_len:
|
||||
i = OFPInstruction.parser(buf, offset)
|
||||
instructions.append(i)
|
||||
offset += i.len
|
||||
if i is not None:
|
||||
instructions.append(i)
|
||||
offset += i.len
|
||||
except exception.OFPTruncatedMessage as e:
|
||||
instructions.append(e.ofpmsg)
|
||||
msg.instructions = instructions
|
||||
@ -2805,7 +2806,9 @@ class OFPInstruction(StringifyMixin):
|
||||
def parser(cls, buf, offset):
|
||||
(type_, len_) = struct.unpack_from('!HH', buf, offset)
|
||||
cls_ = cls._INSTRUCTION_TYPES.get(type_)
|
||||
return cls_.parser(buf, offset)
|
||||
if cls_ is not None:
|
||||
return cls_.parser(buf, offset)
|
||||
return None
|
||||
|
||||
|
||||
@OFPInstruction.register_instruction_type([ofproto.OFPIT_GOTO_TABLE])
|
||||
@ -3551,7 +3554,7 @@ class OFPActionExperimenter(OFPAction):
|
||||
data = buf[(offset + ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE
|
||||
): offset + len_]
|
||||
if experimenter == ofproto_common.NX_EXPERIMENTER_ID:
|
||||
obj = NXAction.parse(data) # noqa
|
||||
obj = NXAction.parse(data) # pytype: disable=name-error # noqa
|
||||
else:
|
||||
obj = OFPActionExperimenterUnknown(experimenter, data)
|
||||
obj.len = len_
|
||||
@ -3932,22 +3935,23 @@ class OFPMultipartReply(MsgBase):
|
||||
ofproto.OFP_MULTIPART_REPLY_PACK_STR, six.binary_type(buf),
|
||||
ofproto.OFP_HEADER_SIZE)
|
||||
stats_type_cls = cls._STATS_MSG_TYPES.get(type_)
|
||||
msg = super(OFPMultipartReply, stats_type_cls).parser(
|
||||
msg = super(OFPMultipartReply, stats_type_cls).parser( # pytype: disable=attribute-error
|
||||
datapath, version, msg_type, msg_len, xid, buf)
|
||||
msg.type = type_
|
||||
msg.flags = flags
|
||||
|
||||
offset = ofproto.OFP_MULTIPART_REPLY_SIZE
|
||||
body = []
|
||||
while offset < msg_len:
|
||||
b = stats_type_cls.cls_stats_body_cls.parser(msg.buf, offset)
|
||||
body.append(b)
|
||||
offset += b.length if hasattr(b, 'length') else b.len
|
||||
if stats_type_cls is not None:
|
||||
offset = ofproto.OFP_MULTIPART_REPLY_SIZE
|
||||
body = []
|
||||
while offset < msg_len:
|
||||
b = stats_type_cls.cls_stats_body_cls.parser(msg.buf, offset)
|
||||
body.append(b)
|
||||
offset += b.length if hasattr(b, 'length') else b.len
|
||||
|
||||
if stats_type_cls.cls_body_single_struct:
|
||||
msg.body = body[0]
|
||||
else:
|
||||
msg.body = body
|
||||
if stats_type_cls.cls_body_single_struct:
|
||||
msg.body = body[0]
|
||||
else:
|
||||
msg.body = body
|
||||
return msg
|
||||
|
||||
|
||||
@ -4577,12 +4581,13 @@ class OFPGroupStats(StringifyMixin):
|
||||
group_stats = cls(*group)
|
||||
|
||||
group_stats.bucket_stats = []
|
||||
total_len = group_stats.length + offset
|
||||
offset += ofproto.OFP_GROUP_STATS_SIZE
|
||||
while total_len > offset:
|
||||
b = OFPBucketCounter.parser(buf, offset)
|
||||
group_stats.bucket_stats.append(b)
|
||||
offset += ofproto.OFP_BUCKET_COUNTER_SIZE
|
||||
if group_stats.length is not None:
|
||||
total_len = group_stats.length + offset
|
||||
offset += ofproto.OFP_GROUP_STATS_SIZE
|
||||
while total_len > offset:
|
||||
b = OFPBucketCounter.parser(buf, offset)
|
||||
group_stats.bucket_stats.append(b)
|
||||
offset += ofproto.OFP_BUCKET_COUNTER_SIZE
|
||||
|
||||
return group_stats
|
||||
|
||||
@ -5770,7 +5775,7 @@ class ONFFlowMonitorRequest(StringifyMixin):
|
||||
match_len = match.length
|
||||
match_hdr_len = ofproto.OFP_MATCH_SIZE - 4 # exclude pad[4]
|
||||
# strip ofp_match header and trailing padding
|
||||
bin_match = bytes(bin_match)[match_hdr_len:match_len]
|
||||
bin_match = bytearray(bin_match)[match_hdr_len:match_len]
|
||||
self.match_len = len(bin_match)
|
||||
|
||||
buf = bytearray()
|
||||
@ -5936,14 +5941,16 @@ class OFPQueueProp(OFPQueuePropHeader):
|
||||
ofproto.OFP_QUEUE_PROP_HEADER_PACK_STR,
|
||||
buf, offset)
|
||||
cls_ = cls._QUEUE_PROP_PROPERTIES.get(property_)
|
||||
p = cls_.parser(buf, offset + ofproto.OFP_QUEUE_PROP_HEADER_SIZE)
|
||||
p.property = property_
|
||||
p.len = len_
|
||||
if property_ == ofproto.OFPQT_EXPERIMENTER:
|
||||
rest = buf[offset + ofproto.OFP_QUEUE_PROP_EXPERIMENTER_SIZE:
|
||||
offset + len_]
|
||||
p.parse_experimenter_data(rest)
|
||||
return p
|
||||
if cls_ is not None:
|
||||
p = cls_.parser(buf, offset + ofproto.OFP_QUEUE_PROP_HEADER_SIZE)
|
||||
p.property = property_
|
||||
p.len = len_
|
||||
if property_ == ofproto.OFPQT_EXPERIMENTER:
|
||||
rest = buf[offset + ofproto.OFP_QUEUE_PROP_EXPERIMENTER_SIZE:
|
||||
offset + len_]
|
||||
p.parse_experimenter_data(rest)
|
||||
return p
|
||||
return None
|
||||
|
||||
|
||||
@OFPQueueProp.register_property(ofproto.OFPQT_MIN_RATE,
|
||||
@ -6017,9 +6024,10 @@ class OFPPacketQueue(StringifyMixin):
|
||||
properties = []
|
||||
while length < len_:
|
||||
queue_prop = OFPQueueProp.parser(buf, offset)
|
||||
properties.append(queue_prop)
|
||||
offset += queue_prop.len
|
||||
length += queue_prop.len
|
||||
if queue_prop is not None:
|
||||
properties.append(queue_prop)
|
||||
offset += queue_prop.len
|
||||
length += queue_prop.len
|
||||
o = cls(queue_id, port, properties)
|
||||
o.len = len_
|
||||
return o
|
||||
@ -6342,6 +6350,10 @@ class OFPSetAsync(MsgBase):
|
||||
self.flow_removed_mask[0], self.flow_removed_mask[1])
|
||||
|
||||
|
||||
class OFPBundleProp(OFPPropBase):
|
||||
_TYPES = {}
|
||||
|
||||
|
||||
@_register_exp_type(ofproto_common.ONF_EXPERIMENTER_ID,
|
||||
ofproto.ONF_ET_BUNDLE_CONTROL)
|
||||
class ONFBundleCtrlMsg(OFPExperimenter):
|
||||
|
||||
@ -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
|
||||
|
||||
@ -191,6 +191,7 @@ class TestOpenFlowController(unittest.TestCase):
|
||||
conf_mock.ofp_ssl_listen_port = port
|
||||
conf_mock.ofp_listen_host = "127.0.0.1"
|
||||
conf_mock.ca_certs = None
|
||||
conf_mock.ciphers = None
|
||||
conf_mock.ctl_cert = os.path.join(this_dir, 'cert.crt')
|
||||
conf_mock.ctl_privkey = os.path.join(this_dir, 'cert.key')
|
||||
c = controller.OpenFlowController()
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -1,85 +0,0 @@
|
||||
# Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import pkg_resources
|
||||
from six.moves import urllib
|
||||
|
||||
from nose.tools import ok_
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
MOD_DIR = os.path.dirname('file://' + sys.modules[__name__].__file__)
|
||||
_RYU_REQUIREMENTS_FILES = [
|
||||
'../../../tools/pip-requires',
|
||||
'../../../tools/optional-requires',
|
||||
]
|
||||
RYU_REQUIREMENTS_FILES = [
|
||||
os.path.join(MOD_DIR, f) for f in _RYU_REQUIREMENTS_FILES]
|
||||
|
||||
OPENSTACK_REQUIREMENTS_REPO = 'https://github.com/openstack/requirements'
|
||||
OPENSTACK_REQUIREMENTS_URL = (
|
||||
'https://github.com/openstack/requirements/raw/master/')
|
||||
_OPENSTACK_REQUIREMENTS_FILES = [
|
||||
'requirements.txt',
|
||||
'global-requirements.txt',
|
||||
]
|
||||
OPENSTACK_REQUIREMENTS_FILES = [
|
||||
urllib.parse.urljoin(OPENSTACK_REQUIREMENTS_URL, f)
|
||||
for f in _OPENSTACK_REQUIREMENTS_FILES]
|
||||
|
||||
|
||||
def _get_requirements(files):
|
||||
requirements = {}
|
||||
for f in files:
|
||||
response = urllib.request.urlopen(f)
|
||||
contents = response.read().decode('utf-8')
|
||||
for r in pkg_resources.parse_requirements(contents):
|
||||
requirements[r.name] = str(r)
|
||||
|
||||
return requirements
|
||||
|
||||
|
||||
OPENSTACK_REQUIREMENTS = _get_requirements(OPENSTACK_REQUIREMENTS_FILES)
|
||||
RYU_REQUIREMENTS = _get_requirements(RYU_REQUIREMENTS_FILES)
|
||||
|
||||
|
||||
class TestRequirements(unittest.TestCase):
|
||||
"""
|
||||
Test whether the requirements of Ryu has no conflict with that
|
||||
of other projects.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_with_openstack_requirements(self):
|
||||
try:
|
||||
for name, req in OPENSTACK_REQUIREMENTS.items():
|
||||
if name in RYU_REQUIREMENTS:
|
||||
ok_(pkg_resources.require(req))
|
||||
except pkg_resources.VersionConflict as e:
|
||||
LOG.exception(
|
||||
'Some requirements of Ryu are conflicting with that of '
|
||||
'OpenStack project: %s', OPENSTACK_REQUIREMENTS_REPO)
|
||||
raise e
|
||||
14
setup.cfg
14
setup.cfg
@ -13,12 +13,12 @@ classifier =
|
||||
Topic :: System :: Networking
|
||||
Natural Language :: English
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 2.7
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.4
|
||||
Programming Language :: Python :: 3.5
|
||||
Programming Language :: Python :: 3.6
|
||||
Programming Language :: Python :: 3.7
|
||||
Programming Language :: Python :: 3.8
|
||||
Programming Language :: Python :: 3.9
|
||||
Operating System :: Unix
|
||||
keywords =
|
||||
openflow
|
||||
@ -55,3 +55,13 @@ setup-hooks =
|
||||
console_scripts =
|
||||
ryu-manager = ryu.cmd.manager:main
|
||||
ryu = ryu.cmd.ryu_base:main
|
||||
|
||||
[pytype]
|
||||
inputs =
|
||||
ryu/controller/
|
||||
ryu/ofproto/ofproto_v1_3*
|
||||
disable =
|
||||
import-error
|
||||
module-attr
|
||||
keep-going =
|
||||
1
|
||||
|
||||
6
setup.py
6
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
|
||||
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
-r ../pip-requirements.txt
|
||||
# NOTE: OpenStack avoids some versions of eventlet, because of the
|
||||
# following issue.
|
||||
# https://github.com/eventlet/eventlet/issues/401
|
||||
eventlet!=0.18.3,>=0.18.2,!=0.20.1,!=0.21.0,!=0.23.0
|
||||
msgpack>=0.3.0 # RPC library, BGP speaker(net_cntl)
|
||||
eventlet==0.31.1
|
||||
msgpack>=0.4.0 # RPC library, BGP speaker(net_cntl)
|
||||
netaddr
|
||||
oslo.config>=2.5.0
|
||||
ovs>=2.6.0 # OVSDB
|
||||
packaging==20.9
|
||||
routes # wsgi
|
||||
six>=1.4.0
|
||||
tinyrpc==0.9.4 # RPC library, BGP speaker(net_cntl)
|
||||
tinyrpc==1.0.4 # RPC library, BGP speaker(net_cntl)
|
||||
webob>=1.2 # wsgi
|
||||
|
||||
@ -4,4 +4,5 @@ mock
|
||||
nose
|
||||
pycodestyle
|
||||
pylint
|
||||
pytype
|
||||
formencode
|
||||
|
||||
23
tox.ini
23
tox.ini
@ -1,5 +1,13 @@
|
||||
[tox]
|
||||
envlist = py27,py34,py35,py36,py37,pypy,pycodestyle,autopep8
|
||||
envlist = py35,py36,py37,py38,py39,pypy,pycodestyle,autopep8,pytype
|
||||
|
||||
[gh-actions]
|
||||
python =
|
||||
3.5: py35
|
||||
3.6: py36, pycodestyle, autopep8, pytype
|
||||
3.7: py37
|
||||
3.8: py38
|
||||
3.9: py39
|
||||
|
||||
[testenv]
|
||||
deps =
|
||||
@ -20,11 +28,6 @@ commands =
|
||||
commands =
|
||||
python ryu/tests/integrated/run_test.py
|
||||
|
||||
[testenv:py27]
|
||||
commands =
|
||||
{[testenv]commands}
|
||||
{[testenv:scenario]commands}
|
||||
|
||||
[testenv:py36]
|
||||
commands =
|
||||
{[testenv]commands}
|
||||
@ -50,6 +53,14 @@ deps =
|
||||
commands =
|
||||
bash -c 'test -z "$(autopep8 --recursive --diff ryu/)"'
|
||||
|
||||
[testenv:pytype]
|
||||
deps =
|
||||
-U
|
||||
--no-cache-dir
|
||||
pytype
|
||||
commands =
|
||||
pytype --jobs 2
|
||||
|
||||
[pycodestyle]
|
||||
exclude = pbr-*,.venv,.tox,.git,doc,dist,tools,vcsversion.py,.pyc,ryu/contrib
|
||||
# W503: line break before binary operator
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user