From 89f6945b7ecc3d6ea058de10268fffe3556f1171 Mon Sep 17 00:00:00 2001 From: Shinpei Muraoka Date: Mon, 11 Jul 2016 10:44:18 +0900 Subject: ofproto/nx_actions: Support missing NXAction Actions to be added are as following. - NXActionDecTtlCntIds - NXActionStackPush - NXActionStackPop - NXActionSample - NXActionOutputReg2 - NXActionRegLoad2 - NXActionController2 Signed-off-by: Shinpei Muraoka Signed-off-by: FUJITA Tomonori --- ryu/ofproto/nicira_ext.py | 14 ++ ryu/ofproto/nx_actions.py | 474 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 480 insertions(+), 8 deletions(-) diff --git a/ryu/ofproto/nicira_ext.py b/ryu/ofproto/nicira_ext.py index c5af140d..5306b59f 100644 --- a/ryu/ofproto/nicira_ext.py +++ b/ryu/ofproto/nicira_ext.py @@ -44,15 +44,22 @@ NXAST_EXIT = 17 NXAST_DEC_TTL = 18 NXAST_FIN_TIMEOUT = 19 NXAST_CONTROLLER = 20 +NXAST_DEC_TTL_CNT_IDS = 21 NXAST_PUSH_MPLS = 23 NXAST_POP_MPLS = 24 NXAST_SET_MPLS_TTL = 25 NXAST_DEC_MPLS_TTL = 26 +NXAST_STACK_PUSH = 27 +NXAST_STACK_POP = 28 +NXAST_SAMPLE = 29 NXAST_SET_MPLS_LABEL = 30 NXAST_SET_MPLS_TC = 31 +NXAST_OUTPUT_REG2 = 32 +NXAST_REG_LOAD2 = 33 NXAST_CONJUNCTION = 34 NXAST_CT = 35 NXAST_NAT = 36 +NXAST_CONTROLLER2 = 37 NX_ACTION_RESUBMIT_PACK_STR = '!HHIHHB3x' NX_ACTION_RESUBMIT_SIZE = 16 @@ -151,6 +158,13 @@ NXST_FLOW = 0 NXST_AGGREGATE = 1 NXST_FLOW_MONITOR = 2 +# enum nx_action_controller2_prop_type +NXAC2PT_MAX_LEN = 0 +NXAC2PT_CONTROLLER_ID = 1 +NXAC2PT_REASON = 2 +NXAC2PT_USERDATA = 3 +NXAC2PT_PAUSE = 4 + NICIRA_HEADER_PACK_STR = '!II' NICIRA_HEADER_SIZE = 16 assert (calcsize(NICIRA_HEADER_PACK_STR) + diff --git a/ryu/ofproto/nx_actions.py b/ryu/ofproto/nx_actions.py index 4cd18946..74ca14a4 100644 --- a/ryu/ofproto/nx_actions.py +++ b/ryu/ofproto/nx_actions.py @@ -280,6 +280,46 @@ def generate(ofp_name, ofpp_name): ofs_nbits, dst_num, self.value) return data + class NXActionRegLoad2(NXAction): + _subtype = nicira_ext.NXAST_REG_LOAD2 + _TYPE = { + 'ascii': [ + 'dst', + 'value', + ] + } + + def __init__(self, dst, value, mask=None, + type_=None, len_=None, experimenter=None, subtype=None): + super(NXActionRegLoad2, self).__init__() + self.dst = dst + self.value = value + self.mask = mask + + @classmethod + def parser(cls, buf): + (n, uv, mask, _len) = ofp.oxm_parse(buf, 0) + dst, value = ofp.oxm_to_user(n, uv, mask) + + if isinstance(value, (tuple, list)): + return cls(dst, value[0], value[1]) + else: + return cls(dst, value, None) + + def serialize_body(self): + data = bytearray() + if self.mask is None: + value = self.value + else: + value = (self.value, self.mask) + self._TYPE['ascii'].append('mask') + + n, value, mask = ofp.oxm_from_user(self.dst, value) + len_ = ofp.oxm_serialize(n, value, mask, data, 0) + msg_pack_into("!%dx" % (14 - len_), data, len_) + + return data + class NXActionNote(NXAction): _subtype = nicira_ext.NXAST_NOTE @@ -357,20 +397,28 @@ def generate(ofp_name, ofpp_name): ] } - def __init__(self, src_field, dst_field, n_bits, src_ofs=0, dst_ofs=0, + def __init__(self, src_field, src_start, src_end, + dst_field, dst_start, dst_end, type_=None, len_=None, experimenter=None, subtype=None): super(NXActionRegMove, self).__init__() - self.n_bits = n_bits - self.src_ofs = src_ofs - self.dst_ofs = dst_ofs self.src_field = src_field + self.src_start = src_start + self.src_end = src_end self.dst_field = dst_field + self.dst_start = dst_start + self.dst_end = dst_end @classmethod def parser(cls, buf): (n_bits, src_ofs, dst_ofs,) = struct.unpack_from( cls._fmt_str, buf, 0) rest = buf[struct.calcsize(NXActionRegMove._fmt_str):] + + src_start = src_ofs + src_end = src_ofs + n_bits - 1 + dst_start = dst_ofs + dst_end = dst_ofs + n_bits - 1 + # src field (n, len) = ofp.oxm_parse_header(rest, 0) src_field = ofp.oxm_to_user_header(n) @@ -380,14 +428,17 @@ def generate(ofp_name, ofpp_name): 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) + return cls(src_field, src_start, src_end, + dst_field, dst_start, dst_end) def serialize_body(self): # fixup data = bytearray() + n_bits = self.src_end - self.src_start + 1 + assert n_bits == self.dst_end - self.dst_start + 1 + msg_pack_into(self._fmt_str, data, 0, - self.n_bits, self.src_ofs, self.dst_ofs) + n_bits, self.src_start, self.dst_start) # src field n = ofp.oxm_from_user_header(self.src_field) ofp.oxm_serialize_header(n, data, len(data)) @@ -495,6 +546,58 @@ def generate(ofp_name, ofpp_name): self.max_len) return data + class NXActionOutputReg2(NXAction): + _subtype = nicira_ext.NXAST_OUTPUT_REG2 + + # start, end, src, max_len + _fmt_str = '!HH4s' + _TYPE = { + 'ascii': [ + 'src', + ] + } + + def __init__(self, + start, + end, + src, + max_len, + type_=None, len_=None, experimenter=None, subtype=None): + super(NXActionOutputReg2, self).__init__() + self.start = start + self.end = end + self.src = src + self.max_len = max_len + + @classmethod + def parser(cls, buf): + (ofs_nbits, + max_len, + oxm_data) = struct.unpack_from( + cls._fmt_str, buf, 0) + start = ofs_nbits >> 6 + end = (ofs_nbits & 0x3f) + start + (n, len_) = ofp.oxm_parse_header(oxm_data, 0) + src = ofp.oxm_to_user_header(n) + return cls(start, + end, + src, + max_len) + + def serialize_body(self): + data = bytearray() + oxm_data = bytearray() + ofs_nbits = (self.start << 6) + (self.end - self.start) + oxm = ofp.oxm_from_user_header(self.src) + ofp.oxm_serialize_header(oxm, oxm_data, 0), + msg_pack_into(self._fmt_str, data, 0, + ofs_nbits, + self.max_len, + six.binary_type(oxm_data)) + offset = len(data) + msg_pack_into("!%dx" % (14 - offset), data, offset) + return data + class NXActionLearn(NXAction): _subtype = nicira_ext.NXAST_LEARN @@ -641,7 +744,270 @@ def generate(ofp_name, ofpp_name): self.reason) return data - # For OpenFlow1.0 only + class NXActionController2(NXAction): + _subtype = nicira_ext.NXAST_CONTROLLER2 + _fmt_str = '!6x' + _PACK_STR = '!HH' + + def __init__(self, + type_=None, len_=None, vendor=None, subtype=None, + **kwargs): + super(NXActionController2, self).__init__() + + for arg in kwargs: + if arg in NXActionController2Prop._NAMES: + setattr(self, arg, kwargs[arg]) + + @classmethod + def parser(cls, buf): + cls_data = {} + offset = 6 + buf_len = len(buf) + while buf_len > offset: + (type_, length) = struct.unpack_from(cls._PACK_STR, buf, offset) + offset += 4 + try: + subcls = NXActionController2Prop._TYPES[type_] + except KeyError: + subcls = NXActionController2PropUnknown + data, size = subcls.parser_prop(buf[offset:], length - 4) + offset += size + cls_data[subcls._arg_name] = data + return cls(**cls_data) + + def serialize_body(self): + body = bytearray() + msg_pack_into(self._fmt_str, body, 0) + prop_list = [] + for arg in self.__dict__: + if arg in NXActionController2Prop._NAMES: + prop_list.append((NXActionController2Prop._NAMES[arg], + self.__dict__[arg])) + prop_list.sort(key=lambda x: x[0].type) + + for subcls, value in prop_list: + body += subcls.serialize_prop(value) + + return body + + class NXActionController2Prop(object): + _TYPES = {} + _NAMES = {} + + @classmethod + def register_type(cls, type_): + def _register_type(subcls): + subcls.type = type_ + NXActionController2Prop._TYPES[type_] = subcls + NXActionController2Prop._NAMES[subcls._arg_name] = subcls + return subcls + + return _register_type + + class NXActionController2PropUnknown(NXActionController2Prop): + + @classmethod + def parser_prop(cls, buf, length): + size = 4 + return buf, size + + @classmethod + def serialize_prop(cls, argment): + data = bytearray() + return data + + @NXActionController2Prop.register_type(nicira_ext.NXAC2PT_MAX_LEN) + class NXActionController2PropMaxLen(NXActionController2Prop): + # max_len + _fmt_str = "!H2x" + _arg_name = "max_len" + + @classmethod + def parser_prop(cls, buf, length): + size = 4 + (max_len,) = struct.unpack_from( + cls._fmt_str, buf, 0) + return max_len, size + + @classmethod + def serialize_prop(cls, max_len): + data = bytearray() + msg_pack_into("!HHH2x", data, 0, + nicira_ext.NXAC2PT_MAX_LEN, + 8, + max_len) + return data + + @NXActionController2Prop.register_type(nicira_ext.NXAC2PT_CONTROLLER_ID) + class NXActionController2PropControllerId(NXActionController2Prop): + # controller_id + _fmt_str = "!H2x" + _arg_name = "controller_id" + + @classmethod + def parser_prop(cls, buf, length): + size = 4 + (controller_id,) = struct.unpack_from( + cls._fmt_str, buf, 0) + return controller_id, size + + @classmethod + def serialize_prop(cls, controller_id): + data = bytearray() + msg_pack_into("!HHH2x", data, 0, + nicira_ext.NXAC2PT_CONTROLLER_ID, + 8, + controller_id) + return data + + @NXActionController2Prop.register_type(nicira_ext.NXAC2PT_REASON) + class NXActionController2PropReason(NXActionController2Prop): + # reason + _fmt_str = "!B3x" + _arg_name = "reason" + + @classmethod + def parser_prop(cls, buf, length): + size = 4 + (reason,) = struct.unpack_from( + cls._fmt_str, buf, 0) + return reason, size + + @classmethod + def serialize_prop(cls, reason): + data = bytearray() + msg_pack_into("!HHB3x", data, 0, + nicira_ext.NXAC2PT_REASON, + 5, + reason) + return data + + @NXActionController2Prop.register_type(nicira_ext.NXAC2PT_USERDATA) + class NXActionController2PropUserData(NXActionController2Prop): + # userdata + _fmt_str = "!B" + _arg_name = "userdata" + + @classmethod + def parser_prop(cls, buf, length): + userdata = [] + offset = 0 + + while offset < length: + u = struct.unpack_from(cls._fmt_str, buf, offset) + userdata.append(u[0]) + offset += 1 + + user_size = utils.round_up(length, 4) + + if user_size > 4 and (user_size % 8) == 0: + size = utils.round_up(length, 4) + 4 + else: + size = utils.round_up(length, 4) + + return userdata, size + + @classmethod + def serialize_prop(cls, userdata): + data = bytearray() + user_buf = bytearray() + user_offset = 0 + for user in userdata: + msg_pack_into('!B', user_buf, user_offset, + user) + user_offset += 1 + + msg_pack_into("!HH", data, 0, + nicira_ext.NXAC2PT_USERDATA, + 4 + user_offset) + data += user_buf + + if user_offset > 4: + user_len = utils.round_up(user_offset, 4) + brank_size = 0 + if (user_len % 8) == 0: + brank_size = 4 + msg_pack_into("!%dx" % (user_len - user_offset + brank_size), + data, 4 + user_offset) + else: + user_len = utils.round_up(user_offset, 4) + + msg_pack_into("!%dx" % (user_len - user_offset), + data, 4 + user_offset) + return data + + @NXActionController2Prop.register_type(nicira_ext.NXAC2PT_PAUSE) + class NXActionController2PropPause(NXActionController2Prop): + _arg_name = "pause" + + @classmethod + def parser_prop(cls, buf, length): + pause = True + size = 4 + return pause, size + + @classmethod + def serialize_prop(cls, pause): + data = bytearray() + msg_pack_into("!HH4x", data, 0, + nicira_ext.NXAC2PT_PAUSE, + 4) + return data + + class NXActionDecTtlCntIds(NXAction): + _subtype = nicira_ext.NXAST_DEC_TTL_CNT_IDS + + # controllers + _fmt_str = '!H4x' + _fmt_len = 6 + + def __init__(self, + cnt_ids, + type_=None, len_=None, experimenter=None, subtype=None): + super(NXActionDecTtlCntIds, self).__init__() + + self.cnt_ids = cnt_ids + + @classmethod + def parser(cls, buf): + (controllers,) = struct.unpack_from( + cls._fmt_str, buf) + + offset = cls._fmt_len + cnt_ids = [] + + for i in range(0, controllers): + id_ = struct.unpack_from('!H', buf, offset) + cnt_ids.append(id_[0]) + offset += 2 + + return cls(cnt_ids) + + def serialize_body(self): + assert isinstance(self.cnt_ids, (tuple, list)) + for i in self.cnt_ids: + assert isinstance(i, six.integer_types) + + controllers = len(self.cnt_ids) + + data = bytearray() + msg_pack_into(self._fmt_str, data, 0, + controllers) + offset = self._fmt_len + + for id_ in self.cnt_ids: + msg_pack_into('!H', data, offset, id_) + offset += 2 + + id_len = (utils.round_up(controllers, 4) - + controllers) + + if id_len != 0: + msg_pack_into('%dx' % id_len * 2, data, offset) + + return data + + # Use in only OpenFlow1.0 class NXActionMplsBase(NXAction): # ethertype _fmt_str = '!H4x' @@ -767,6 +1133,91 @@ def generate(ofp_name, ofpp_name): self.tc) return data + class NXActionStackBase(NXAction): + # start, field, end + _fmt_str = '!H4sH' + _TYPE = { + 'ascii': [ + 'field', + ] + } + + def __init__(self, + field, + start, + end, + type_=None, len_=None, experimenter=None, subtype=None): + super(NXActionStackBase, self).__init__() + self.field = field + self.start = start + self.end = end + + @classmethod + def parser(cls, buf): + (start, oxm_data, end) = struct.unpack_from( + cls._fmt_str, buf, 0) + (n, len_) = ofp.oxm_parse_header(oxm_data, 0) + field = ofp.oxm_to_user_header(n) + return cls(field, start, end) + + def serialize_body(self): + data = bytearray() + oxm_data = bytearray() + oxm = ofp.oxm_from_user_header(self.field) + ofp.oxm_serialize_header(oxm, oxm_data, 0) + msg_pack_into(self._fmt_str, data, 0, + self.start, + six.binary_type(oxm_data), + self.end) + offset = len(data) + msg_pack_into("!%dx" % (12 - offset), data, offset) + return data + + class NXActionStackPush(NXActionStackBase): + _subtype = nicira_ext.NXAST_STACK_PUSH + + class NXActionStackPop(NXActionStackBase): + _subtype = nicira_ext.NXAST_STACK_POP + + class NXActionSample(NXAction): + _subtype = nicira_ext.NXAST_SAMPLE + + # probability, collector_set_id, obs_domain_id, obs_point_id + _fmt_str = '!HIII' + + def __init__(self, + probability, + collector_set_id=0, + obs_domain_id=0, + obs_point_id=0, + type_=None, len_=None, experimenter=None, subtype=None): + super(NXActionSample, self).__init__() + self.probability = probability + self.collector_set_id = collector_set_id + self.obs_domain_id = obs_domain_id + self.obs_point_id = obs_point_id + + @classmethod + def parser(cls, buf): + (probability, + collector_set_id, + obs_domain_id, + obs_point_id) = struct.unpack_from( + cls._fmt_str, buf, 0) + return cls(probability, + collector_set_id, + obs_domain_id, + obs_point_id) + + def serialize_body(self): + data = bytearray() + msg_pack_into(self._fmt_str, data, 0, + self.probability, + self.collector_set_id, + self.obs_domain_id, + self.obs_point_id) + return data + class NXActionFinTimeout(NXAction): _subtype = nicira_ext.NXAST_FIN_TIMEOUT @@ -1182,6 +1633,7 @@ def generate(ofp_name, ofpp_name): 'NXActionSetQueue', 'NXActionPopQueue', 'NXActionRegLoad', + 'NXActionRegLoad2', 'NXActionNote', 'NXActionSetTunnel', 'NXActionSetTunnel64', @@ -1189,16 +1641,22 @@ def generate(ofp_name, ofpp_name): 'NXActionResubmit', 'NXActionResubmitTable', 'NXActionOutputReg', + 'NXActionOutputReg2', 'NXActionLearn', 'NXActionExit', 'NXActionDecTtl', 'NXActionController', + 'NXActionController2', + 'NXActionDecTtlCntIds', 'NXActionPushMpls', 'NXActionPopMpls', 'NXActionSetMplsTtl', 'NXActionDecMplsTtl', 'NXActionSetMplsLabel', 'NXActionSetMplsTc', + 'NXActionStackPush', + 'NXActionStackPop', + 'NXActionSample', 'NXActionFinTimeout', 'NXActionConjunction', 'NXActionMultipath', -- cgit v1.2.3