diff --git a/ryu/ofproto/nx_actions.py b/ryu/ofproto/nx_actions.py new file mode 100644 index 00000000..b8879e6c --- /dev/null +++ b/ryu/ofproto/nx_actions.py @@ -0,0 +1,154 @@ +# Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. +# Copyright (C) 2015 YAMAMOTO Takashi +# +# 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) diff --git a/ryu/ofproto/ofproto_v1_3_parser.py b/ryu/ofproto/ofproto_v1_3_parser.py index 1d2d671b..e9b4b293 100644 --- a/ryu/ofproto/ofproto_v1_3_parser.py +++ b/ryu/ofproto/ofproto_v1_3_parser.py @@ -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' +)