Implement nx_action_reg_move for OpenFlow 1.3

Also, improve experimenter action related code so that
it can handle unknown actions as unknown.

Only OpenFlow 1.3 for now because this is planned to be used
for Neutron OVS agent and 1.3 is the version to be used there.
(https://blueprints.launchpad.net/neutron/+spec/ovs-ofctl-to-python)

Following the style of oxm_fields, make an OpenFlow version independent
module generate OpenFlow version specific code so that it's easier to
add the functionality to other OpenFlow versions later.

Signed-off-by: YAMAMOTO Takashi <yamamoto@valinux.co.jp>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
YAMAMOTO Takashi 2015-01-19 16:48:26 +09:00 committed by FUJITA Tomonori
parent 1a03f4c650
commit cbb387f8eb
2 changed files with 193 additions and 7 deletions

154
ryu/ofproto/nx_actions.py Normal file
View File

@ -0,0 +1,154 @@
# Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
# Copyright (C) 2015 YAMAMOTO Takashi <yamamoto at valinux co jp>
#
# 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 struct
from ryu import utils
from ryu.ofproto import nicira_ext
from ryu.ofproto import ofproto_common
from ryu.ofproto.ofproto_parser import msg_pack_into
def generate(ofp_name, ofpp_name):
import sys
import string
import functools
ofp = sys.modules[ofp_name]
ofpp = sys.modules[ofpp_name]
class NXAction(ofpp.OFPActionExperimenter):
_fmt_str = '!H' # subtype
_subtypes = {}
experimenter = ofproto_common.NX_EXPERIMENTER_ID
def __init__(self):
super(NXAction, self).__init__(experimenter=self.experimenter)
self.subtype = self.subtype
@classmethod
def parse(cls, buf):
fmt_str = NXAction._fmt_str
(subtype,) = struct.unpack_from(fmt_str, buf, 0)
subtype_cls = cls._subtypes.get(subtype)
rest = buf[struct.calcsize(fmt_str):]
if subtype_cls is None:
return NXActionUnknown(subtype, rest)
return subtype_cls.parse(rest)
def serialize(self, buf, offset):
super(NXAction, self).serialize(buf, offset)
msg_pack_into(NXAction._fmt_str,
buf,
offset + ofp.OFP_ACTION_EXPERIMENTER_HEADER_SIZE,
self.subtype)
@classmethod
def register(cls, subtype_cls):
assert subtype_cls.subtype is not cls._subtypes
cls._subtypes[subtype_cls.subtype] = subtype_cls
class NXActionUnknown(NXAction):
def __init__(self, subtype, data=None,
type_=None, len_=None, experimenter=None):
self.subtype = subtype
super(NXActionUnknown, self).__init__()
self.data = data
@classmethod
def parse(cls, subtype, buf):
return cls(data=buf)
def serialize(self, buf, offset):
# fixup
data = self.data
if data is None:
data = bytearray()
payload_offset = (
ofp.OFP_ACTION_EXPERIMENTER_HEADER_SIZE +
struct.calcsize(NXAction._fmt_str)
)
self.len = utils.round_up(payload_offset + len(data), 8)
super(NXActionUnknown, self).serialize(buf, offset)
buf += data
class NXActionRegMove(NXAction):
subtype = nicira_ext.NXAST_REG_MOVE
_fmt_str = '!HHH' # n_bits, src_ofs, dst_ofs
# Followed by OXM fields (src, dst) and padding to 8 bytes boundary
def __init__(self, src_field, dst_field, n_bits, src_ofs=0, dst_ofs=0,
type_=None, len_=None, experimenter=None, subtype=None):
super(NXActionRegMove, self).__init__()
self.experimenter = ofproto_common.NX_EXPERIMENTER_ID
self.subtype = self.subtype
self.n_bits = n_bits
self.src_ofs = src_ofs
self.dst_ofs = dst_ofs
self.src_field = src_field
self.dst_field = dst_field
@classmethod
def parse(cls, buf):
(n_bits, src_ofs, dst_ofs,) = struct.unpack_from(
NXActionRegMove._fmt_str, buf, 0)
rest = buf[struct.calcsize(NXActionRegMove._fmt_str):]
# src field
(n, len) = ofp.oxm_parse_header(rest, 0)
src_field = ofp.oxm_to_user_header(n)
rest = rest[len:]
# dst field
(n, len) = ofp.oxm_parse_header(rest, 0)
dst_field = ofp.oxm_to_user_header(n)
rest = rest[len:]
# ignore padding
return cls(src_field, dst_field=dst_field, n_bits=n_bits,
src_ofs=src_ofs, dst_ofs=dst_ofs)
def serialize(self, buf, offset):
# fixup
data = bytearray()
msg_pack_into(NXActionRegMove._fmt_str, data, 0,
self.n_bits, self.src_ofs, self.dst_ofs)
# src field
n = ofp.oxm_from_user_header(self.src_field)
ofp.oxm_serialize_header(n, data, len(data))
# dst field
n = ofp.oxm_from_user_header(self.dst_field)
ofp.oxm_serialize_header(n, data, len(data))
payload_offset = (
ofp.OFP_ACTION_EXPERIMENTER_HEADER_SIZE +
struct.calcsize(NXAction._fmt_str)
)
self.len = utils.round_up(payload_offset + len(data), 8)
super(NXActionRegMove, self).serialize(buf, offset)
msg_pack_into('!%ds' % len(data), buf, offset + payload_offset,
bytes(data))
def add_attr(k, v):
setattr(ofpp, k, v)
add_attr('NXAction', NXAction)
add_attr('NXActionUnknown', NXActionUnknown)
actions = [
'NXActionRegMove',
]
vars = locals()
for a in actions:
cls = vars[a]
add_attr(a, cls)
NXAction.register(cls)

View File

@ -48,6 +48,7 @@ from ryu.lib import mac
from ryu import utils
from ofproto_parser import StringifyMixin, MsgBase, msg_pack_into, msg_str_attr
from . import ether
from . import nicira_ext
from . import ofproto_parser
from . import ofproto_common
from . import ofproto_v1_3 as ofproto
@ -3225,12 +3226,12 @@ class OFPActionExperimenter(OFPAction):
experimenter Experimenter ID
================ ======================================================
"""
def __init__(self, experimenter, data=None, type_=None, len_=None):
def __init__(self, experimenter):
super(OFPActionExperimenter, self).__init__()
self.type = ofproto.OFPAT_EXPERIMENTER
self.experimenter = experimenter
self.data = data
self.len = (utils.round_up(len(data), 8) +
ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE)
self.len = None
@classmethod
def parser(cls, buf, offset):
@ -3238,13 +3239,36 @@ class OFPActionExperimenter(OFPAction):
ofproto.OFP_ACTION_EXPERIMENTER_HEADER_PACK_STR, buf, offset)
data = buf[(offset + ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE
): offset + len_]
return cls(experimenter, data)
if experimenter == ofproto_common.NX_EXPERIMENTER_ID:
obj = NXAction.parse(data)
else:
obj = OFPActionExperimenterUnknown(experimenter, data)
obj.len = len_
return obj
def serialize(self, buf, offset):
msg_pack_into(ofproto.OFP_ACTION_EXPERIMENTER_HEADER_PACK_STR,
buf, offset, self.type, self.len, self.experimenter)
if self.data:
buf += self.data
class OFPActionExperimenterUnknown(OFPActionExperimenter):
def __init__(self, experimenter, data=None, type_=None, len_=None):
super(OFPActionExperimenterUnknown,
self).__init__(experimenter=experimenter)
self.data = data
def serialize(self, buf, offset):
# fixup
data = self.data
if data is None:
data = bytearray()
self.len = (utils.round_up(len(data), 8) +
ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE)
super(OFPActionExperimenterUnknown, self).serialize(buf, offset)
msg_pack_into('!%ds' % len(self.data),
buf,
offset + ofproto.OFP_ACTION_EXPERIMENTER_HEADER_SIZE,
self.data)
class OFPBucket(StringifyMixin):
@ -6014,3 +6038,11 @@ class OFPSetAsync(MsgBase):
self.packet_in_mask[0], self.packet_in_mask[1],
self.port_status_mask[0], self.port_status_mask[1],
self.flow_removed_mask[0], self.flow_removed_mask[1])
import nx_actions
nx_actions.generate(
'ryu.ofproto.ofproto_v1_3',
'ryu.ofproto.ofproto_v1_3_parser'
)