# Copyright (C) 2013-2015 Nippon Telegraph and Telephone Corporation. # Copyright (C) 2013-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. # there are two representations of value and mask this module deal with. # # "user" # (value, mask) or value. the latter means no mask. # value and mask are strings. # # "internal" # value and mask are on-wire bytes. # mask is None if no mask. # There are two types of OXM/NXM headers. # # 32-bit OXM/NXM header # +-------------------------------+-------------+-+---------------+ # | class | field |m| length | # +-------------------------------+-------------+-+---------------+ # # 64-bit experimenter OXM header # +-------------------------------+-------------+-+---------------+ # | class (OFPXMC_EXPERIMENTER) | field |m| length | # +-------------------------------+-------------+-+---------------+ # | experimenter ID | # +---------------------------------------------------------------+ # NOTE: OpenFlow Spec 1.5 mandates that Experimenter OXMs encode # the experimenter type in the oxm_field field of the OXM header # (EXT-380). # NOTE: EXT-256 had a variation of experimenter OXM header. # It has been rectified since then. Currently this implementation # supports only the old version. # # ONF EXT-256 (old, exp_type = 2560) # +-------------------------------+-------------+-+---------------+ # | class (OFPXMC_EXPERIMENTER) | ????? |m| length | # +-------------------------------+-------------+-+---------------+ # | experimenter ID (ONF_EXPERIMENTER_ID) | # +-------------------------------+---------------+---------------+ # | exp_type (PBB_UCA=2560) | pbb_uca | # +-------------------------------+---------------+ # # ONF EXT-256 (new, oxm_field = 41) # +-------------------------------+-------------+-+---------------+ # | class (OFPXMC_EXPERIMENTER) | PBB_UCA=41 |m| length | # +-------------------------------+-------------+-+---------------+ # | experimenter ID (ONF_EXPERIMENTER_ID) | # +-------------------------------+---------------+---------------+ # | reserved, should be zero | pbb_uca | # +-------------------------------+---------------+ from ryu.ofproto.oxx_fields import ( _from_user, _from_user_header, _to_user, _to_user_header, _field_desc, _normalize_user, _parse, _parse_header, _serialize, _serialize_header) from ryu.ofproto import ofproto_common OFPXMC_NXM_0 = 0 # Nicira Extended Match (NXM_OF_) OFPXMC_NXM_1 = 1 # Nicira Extended Match (NXM_NX_) OFPXMC_OPENFLOW_BASIC = 0x8000 OFPXMC_PACKET_REGS = 0x8001 OFPXMC_EXPERIMENTER = 0xffff class _OxmClass(object): def __init__(self, name, num, type_): self.name = name self.oxm_field = num self.oxm_type = num | (self._class << 7) # TODO(yamamoto): Clean this up later. # Probably when we drop EXT-256 style experimenter OXMs. self.num = self.oxm_type self.type = type_ class OpenFlowBasic(_OxmClass): _class = OFPXMC_OPENFLOW_BASIC class PacketRegs(_OxmClass): _class = OFPXMC_PACKET_REGS class _Experimenter(_OxmClass): _class = OFPXMC_EXPERIMENTER def __init__(self, name, num, type_): super(_Experimenter, self).__init__(name, num, type_) self.num = (self.experimenter_id, self.oxm_type) self.exp_type = self.oxm_field class ONFExperimenter(_Experimenter): experimenter_id = ofproto_common.ONF_EXPERIMENTER_ID class OldONFExperimenter(_Experimenter): # This class is for the old version of EXT-256 experimenter_id = ofproto_common.ONF_EXPERIMENTER_ID def __init__(self, name, num, type_): super(OldONFExperimenter, self).__init__(name, 0, type_) self.num = (self.experimenter_id, num) self.exp_type = 2560 class NiciraExperimenter(_Experimenter): experimenter_id = ofproto_common.NX_EXPERIMENTER_ID class NiciraExtended0(_OxmClass): """Nicira Extended Match (NXM_0) NXM header format is same as 32-bit (non-experimenter) OXMs. """ _class = OFPXMC_NXM_0 class NiciraExtended1(_OxmClass): """Nicira Extended Match (NXM_1) NXM header format is same as 32-bit (non-experimenter) OXMs. """ _class = OFPXMC_NXM_1 def generate(modname): import sys import functools mod = sys.modules[modname] def add_attr(k, v): setattr(mod, k, v) for i in mod.oxm_types: if isinstance(i.num, tuple): continue if i._class != OFPXMC_OPENFLOW_BASIC: continue uk = i.name.upper() ofpxmt = i.oxm_field td = i.type add_attr('OFPXMT_OFB_' + uk, ofpxmt) add_attr('OXM_OF_' + uk, mod.oxm_tlv_header(ofpxmt, td.size)) add_attr('OXM_OF_' + uk + '_W', mod.oxm_tlv_header_w(ofpxmt, td.size)) # 'oxx' indicates the OpenFlow Extensible class type. # eg.) 'oxm' indicates that this class is OXM class. oxx = 'oxm' name_to_field = dict((f.name, f) for f in mod.oxm_types) num_to_field = dict((f.num, f) for f in mod.oxm_types) # create functions by using oxx_fields module. add_attr('oxm_from_user', functools.partial(_from_user, oxx, name_to_field)) add_attr('oxm_from_user_header', functools.partial(_from_user_header, oxx, name_to_field)) add_attr('oxm_to_user', functools.partial(_to_user, oxx, num_to_field)) add_attr('oxm_to_user_header', functools.partial(_to_user_header, oxx, num_to_field)) add_attr('_oxm_field_desc', # oxx is not required functools.partial(_field_desc, num_to_field)) add_attr('oxm_normalize_user', functools.partial(_normalize_user, oxx, mod)) add_attr('oxm_parse', # oxx is not required functools.partial(_parse, mod)) add_attr('oxm_parse_header', # oxx is not required functools.partial(_parse_header, mod)) add_attr('oxm_serialize', functools.partial(_serialize, oxx, mod)) add_attr('oxm_serialize_header', functools.partial(_serialize_header, oxx, mod)) add_attr('oxm_to_jsondict', _to_jsondict) add_attr('oxm_from_jsondict', _from_jsondict) def _to_jsondict(k, uv): if isinstance(uv, tuple): (value, mask) = uv else: value = uv mask = None return {"OXMTlv": {"field": k, "value": value, "mask": mask}} def _from_jsondict(j): tlv = j['OXMTlv'] field = tlv['field'] value = tlv['value'] mask = tlv.get('mask') if mask is None: uv = value else: uv = (value, mask) return (field, uv)