blob: cfece7d34acf9f1d49f3faea03195bfbb989a092 [file] [log] [blame]
Andreas Wundsam27303462013-07-16 12:52:35 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
Andreas Wundsam40e14f72013-05-06 14:49:08 -070028# Prototype of an Intermediate Object model for the java code generator
29# A lot of this stuff could/should probably be merged with the python utilities
30
Andreas Wundsam27303462013-07-16 12:52:35 -070031import collections
Andreas Wundsam5204de22013-07-30 11:34:45 -070032from collections import namedtuple, defaultdict, OrderedDict
Andreas Wundsam27303462013-07-16 12:52:35 -070033import logging
Andreas Wundsam40e14f72013-05-06 14:49:08 -070034import os
35import pdb
36import re
37
Andreas Wundsam5204de22013-07-30 11:34:45 -070038from generic_utils import find, memoize, OrderedSet, OrderedDefaultDict
Andreas Wundsamc8912c12013-11-15 13:44:48 -080039from loxi_globals import OFVersions
40import loxi_globals
Andreas Wundsam27303462013-07-16 12:52:35 -070041from loxi_ir import *
Andreas Wundsam5204de22013-07-30 11:34:45 -070042import loxi_utils.loxi_utils as loxi_utils
Andreas Wundsam5204de22013-07-30 11:34:45 -070043import test_data
Andreas Wundsam40e14f72013-05-06 14:49:08 -070044
Andreas Wundsam27303462013-07-16 12:52:35 -070045import java_gen.java_type as java_type
Andreas Wundsame0d52be2013-08-22 07:52:13 -070046from java_gen.java_type import erase_type_annotation
Andreas Wundsam40e14f72013-05-06 14:49:08 -070047
Andreas Wundsamc8912c12013-11-15 13:44:48 -080048logger = logging.getLogger(__name__)
49
Andreas Wundsam27303462013-07-16 12:52:35 -070050class JavaModel(object):
Andreas Wundsamf1949682013-09-23 14:48:31 -070051 # registry for enums that should not be generated
52 # set(${java_enum_name})
Andreas Wundsamacd57d52013-10-18 17:35:01 -070053 enum_blacklist = set(("OFDefinitions", "OFPortNo", "OFVlanId", "OFGroup"))
Andreas Wundsamf1949682013-09-23 14:48:31 -070054 # registry for enum *entry* that should not be generated
55 # map: ${java_enum_name} -> set(${java_entry_entry_name})
Andreas Wundsam43526532013-08-01 22:03:50 -070056 enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
Andreas Wundsamf1949682013-09-23 14:48:31 -070057
58 # registry of interfaces that should not be generated
59 # set(java_names)
Andreas Wundsambe168f72013-08-03 22:49:35 -070060 # OFUint structs are there for god-knows what in loci. We certainly don't need them.
61 interface_blacklist = set( ("OFUint8", "OFUint32",))
Andreas Wundsamf1949682013-09-23 14:48:31 -070062 # registry of interface properties that should not be generated
63 # map: $java_type -> set(java_name_property)
Rich Lane97fd13d2013-11-13 11:25:48 -080064 read_blacklist = defaultdict(lambda: set(),
65 OFExperimenter=set(('data','subtype')),
66 OFActionExperimenter=set(('data',)),
67 OFExperimenterStatsRequest=set(('data','subtype')),
68 OFExperimenterStatsReply=set(('data','subtype')))
Andreas Wundsamf1949682013-09-23 14:48:31 -070069 # map: $java_type -> set(java_name_property)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070070 write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
Andreas Wundsamf1949682013-09-23 14:48:31 -070071 # interfaces that are virtual
Andreas Wundsam001b1822013-08-02 22:25:55 -070072 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070073
Andreas Wundsamf1949682013-09-23 14:48:31 -070074 # Registry of nullable properties:
75 # ${java_class_name} -> set(${java_property_name})
76 nullable_map = defaultdict(lambda: set(),
77 )
78
79 # represents a subgroup of a bitmask enum that is actualy a normal enumerable within a masked part of the enum
80 # e.g., the flags STP.* in OF1.0 port state are bit mask entries, but instead enumerables according to the mask "STP_MASK"
81 # name: a name for the group
82 # mask: java name of the enum entry that defines the mask
83 # members: set of names of the members of the group
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -070084 MaskedEnumGroup = namedtuple("MaskedEnumGroup", ("name", "mask", "members"))
85
Andreas Wundsamf1949682013-09-23 14:48:31 -070086 # registry of MaskedEnumGroups (see above).
87 # map: ${java_enum_name}: tuple(MaskedEnumGroup)
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -070088 masked_enum_groups = defaultdict(lambda: (),
Andreas Wundsamaebe5182013-09-24 13:01:07 -070089 OFPortState = (MaskedEnumGroup("stp_flags", mask="STP_MASK", members=set(("STP_LISTEN", "STP_LEARN", "STP_FORWARD", "STP_BLOCK"))), ),
90 OFConfigFlags = (
91 MaskedEnumGroup("frag_flags", mask="FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
Andreas Wundsam376cef52013-09-24 13:52:18 -070092 ),
93 OFTableConfig = (
94 MaskedEnumGroup("table_miss_flags", mask="TABLE_MISS_MASK", members=set(("TABLE_MISS_CONTROLLER", "TABLE_MISS_CONTINUE", "TABLE_MISS_DROP"))),
95 ),
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -070096 )
97
Andreas Wundsamf1949682013-09-23 14:48:31 -070098 # represents a metadata property associated with an EnumClass
99 # name:
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700100 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700101 """
102 represents a metadata property associated with an Enum Class
103 @param name name of metadata property
104 @param type java_type instance describing the type
105 @value: Generator function f(entry) that generates the value
106 """
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700107 @property
108 def variable_name(self):
109 return self.name[0].lower() + self.name[1:]
110
111 @property
112 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700113 prefix = "is" if self.type == java_type.boolean else "get"
114 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700115
Andreas Wundsamf1949682013-09-23 14:48:31 -0700116 """ Metadata container. """
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700117 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
118
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700119 def gen_port_speed(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700120 """ Generator function for OFortFeatures.PortSpeed"""
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700121 splits = enum_entry.name.split("_")
122 if len(splits)>=2:
123 m = re.match(r'\d+[MGTP]B', splits[1])
124 if m:
125 return "PortSpeed.SPEED_{}".format(splits[1])
126 return "PortSpeed.SPEED_NONE";
127
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700128 def gen_stp_state(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700129 """ Generator function for OFPortState.StpState"""
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700130 splits = enum_entry.name.split("_")
131 if len(splits)>=1:
132 if splits[0] == "STP":
133 return "true"
134 return "false"
135
Andreas Wundsamf1949682013-09-23 14:48:31 -0700136 # registry for metadata properties for enums
137 # map: ${java_enum_name}: OFEnumMetadata
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700138 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
Rob Vaterlausa049dee2013-09-18 16:18:37 -0700139 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
140 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700141 )
142
Andreas Wundsam27303462013-07-16 12:52:35 -0700143 @property
144 @memoize
145 def versions(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800146 return OrderedSet( JavaOFVersion(ir_version) for ir_version in OFVersions.target_versions)
Andreas Wundsam27303462013-07-16 12:52:35 -0700147
148 @property
149 @memoize
150 def interfaces(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800151 interfaces = [ JavaOFInterface(ir_class) for ir_class in loxi_globals.unified.classes ]
Andreas Wundsambe168f72013-08-03 22:49:35 -0700152 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
153
Andreas Wundsam27303462013-07-16 12:52:35 -0700154 return interfaces
155
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700156 @memoize
157 def interface_by_name(self, name):
158 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
159
Andreas Wundsam27303462013-07-16 12:52:35 -0700160 @property
161 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700162 def all_classes(self):
163 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
164
165 @property
166 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700167 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700168 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700169
170 for version in self.versions:
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800171 logger.info("version: {}".format(version.ir_version))
172 of_protocol = loxi_globals.ir[version.ir_version]
Andreas Wundsam27303462013-07-16 12:52:35 -0700173 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700174 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700175
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700176 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
177 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700178
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700179 # inelegant - need java name here
180 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700181 return enums
182
183 @memoize
184 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700185 res = find(lambda e: e.name == name, self.enums)
186 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700187 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700188 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700189
Andreas Wundsam5204de22013-07-30 11:34:45 -0700190 @property
191 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700192 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700193 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700194
195 factories = OrderedDict()
196
197 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
198 for base_class in sub_factory_classes:
199 package = base_class[2:].lower()
200 remove_prefix = base_class[2].lower() + base_class[3:]
201
202 # HACK need to have a better way to deal with parameterized base classes
203 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
204
205 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700206 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={}, xid_generator=False)
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700207
208 factories[""] = OFFactory(
209 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700210 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700211 remove_prefix="",
212 members=[], base_class="OFMessage", sub_factories=OrderedDict(
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700213 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ),
214 xid_generator=True)
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700215
216 for i in self.interfaces:
217 for n, factory in factories.items():
218 if n == "":
219 factory.members.append(i)
220 break
221 else:
222 super_class = self.interface_by_name(n)
223 if i.is_instance_of(super_class):
224 factory.members.append(i)
225 break
226 return factories.values()
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800227
Yotam Harchol595c6442013-09-27 16:29:08 -0700228 @memoize
229 def factory_of(self, interface):
230 for factory in self.of_factories:
231 if interface in factory.members:
232 return factory
233 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700234
235 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700236 """ return wether or not to generate implementation class clazz.
237 Now true for everything except OFTableModVer10.
238 @param clazz JavaOFClass instance
239 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700240 if clazz.interface.name.startswith("OFMatchV"):
241 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700242 elif clazz.name == "OFTableModVer10":
243 # tablemod ver 10 is a hack and has no oftype defined
244 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700245 if loxi_utils.class_is_message(clazz.interface.c_name):
246 return True
247 if loxi_utils.class_is_oxm(clazz.interface.c_name):
248 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700249 if loxi_utils.class_is_action(clazz.interface.c_name):
250 return True
251 if loxi_utils.class_is_instruction(clazz.interface.c_name):
252 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700253 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700254 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700255
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800256 @property
257 @memoize
258 def oxm_map(self):
259 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
260 return OrderedDict( (oxm.name, OxmMapEntry(type_name=oxm.member_by_name("value").java_type.public_type,
261 value=re.sub(r'^of_oxm_', r'', re.sub(r'_masked$', r'', oxm.ir_class.name)).upper(),
262 masked=oxm.ir_class.name.endswith("_masked")))
263 for oxm in self.interfaces if oxm.ir_class.is_subclassof("of_oxm") )
Andreas Wundsam5204de22013-07-30 11:34:45 -0700264
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700265class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories", "xid_generator"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700266 @property
267 def factory_classes(self):
268 return [ OFFactoryClass(
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800269 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.dotless_version),
270 name="{}Ver{}".format(self.name, version.dotless_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700271 interface=self,
272 version=version
273 ) for version in model.versions ]
274
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700275 def method_name(self, member, builder=True):
276 n = member.variable_name
277 if n.startswith(self.remove_prefix):
278 n = n[len(self.remove_prefix):]
279 n = n[0].lower() + n[1:]
280 if builder:
281 return "build" + n[0].upper() + n[1:]
282 else:
283 return n
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800284
Yotam Harchol595c6442013-09-27 16:29:08 -0700285 def of_version(self, version):
286 for fc in self.factory_classes:
287 if fc.version == version:
288 return fc
289 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700290
291OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700292class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
293 @property
294 def base_class(self):
295 return self.interface.base_class
296
297 @property
298 def versioned_base_class(self):
299 base_class_interface = model.interface_by_name(self.interface.base_class)
300 if base_class_interface and base_class_interface.has_version(self.version):
301 return base_class_interface.versioned_class(self.version)
302 else:
303 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700304
Andreas Wundsam27303462013-07-16 12:52:35 -0700305model = JavaModel()
306
307#######################################################################
308### OFVersion
309#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700310
311class JavaOFVersion(object):
312 """ Models a version of OpenFlow. contains methods to convert the internal
313 Loxi version to a java constant / a string """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800314 def __init__(self, ir_version):
315 assert isinstance(ir_version, OFVersion)
316 self.ir_version = ir_version
317 self.int_version = self.ir_version.wire_version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700318
319 @property
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800320 def dotless_version(self):
321 return self.ir_version.version.replace(".", "")
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700322
323 @property
324 def constant_version(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800325 return "OF_" + self.dotless_version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700326
Andreas Wundsam27303462013-07-16 12:52:35 -0700327 def __repr__(self):
328 return "JavaOFVersion(%d)" % self.int_version
329
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700330 def __str__(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800331 return self.ir_version.version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700332
Andreas Wundsam27303462013-07-16 12:52:35 -0700333 def __hash__(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800334 return hash(self.ir_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700335
336 def __eq__(self, other):
337 if other is None or type(self) != type(other):
338 return False
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800339 return (self.ir_version,) == (other.ir_version,)
Andreas Wundsam27303462013-07-16 12:52:35 -0700340
341#######################################################################
342### Interface
343#######################################################################
344
345class JavaOFInterface(object):
346 """ Models an OpenFlow Message class for the purpose of the java class.
347 Version agnostic, in contrast to the loxi_ir python model.
348 """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800349 def __init__(self, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700350 """"
351 @param c_name: loxi style name (e.g., of_flow_add)
352 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
353 """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800354 self.ir_class = ir_class
355 self.c_name = ir_class.name
356 self.version_map = { JavaOFVersion(v): c for v,c in ir_class.version_classes.items() }
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700357 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800358 self.name = java_type.name_c_to_caps_camel(self.c_name) if self.c_name != "of_header" else "OFMessage"
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700359 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700360 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700361 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700362 # name for use in constants: FLOW_ADD
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800363 self.constant_name = self.c_name.upper().replace("OF_", "")
Andreas Wundsam27303462013-07-16 12:52:35 -0700364
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700365 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700366 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700367 if self.name != parent_interface:
368 self.parent_interface = parent_interface
369 else:
370 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700371
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700372 @property
373 @memoize
374 def all_parent_interfaces(self):
375 return [ "OFObject" ] + \
376 ([ self.parent_interface ] if self.parent_interface else [] )+ \
377 self.additional_parent_interfaces
378 @property
379 @memoize
380 def additional_parent_interfaces(self):
381 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
382 m = re.match(r'(.*)Request$', self.name)
383 if m:
384 reply_name = m.group(1) + "Reply"
385 if model.interface_by_name(reply_name):
386 return ["OFRequest<%s>" % reply_name ]
387 return []
388
389
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700390 def is_instance_of(self, other_class):
391 if self == other_class:
392 return True
393 parent = self.super_class
394 if parent is None:
395 return False
396 else:
397 return parent.is_instance_of(other_class)
398
399 @property
400 def super_class(self):
401 if not self.parent_interface:
402 return None
403 else:
404 return model.interface_by_name(self.parent_interface)
405
406
407 def inherited_declaration(self, type_spec="?"):
408 if self.type_annotation:
409 return "%s<%s>" % (self.name, type_spec)
410 else:
411 return "%s" % self.name
412
413 @property
414 def type_variable(self):
415 if self.type_annotation:
416 return "<T>"
417 else:
418 return "";
419
Andreas Wundsam27303462013-07-16 12:52:35 -0700420 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700421 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
422 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
423 # model (note, that the loxi model is on versioned classes). Should check/infer the
424 # inheritance information from the versioned lox_ir classes.
Andreas Wundsamd6b0cb02013-09-28 18:55:56 -0700425 if re.match(r'OFStatsRequest$', self.name):
426 return ("", "OFMessage", "T extends OFStatsReply")
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800427 elif self.ir_class.is_subclassof('of_stats_request'):
Andreas Wundsam2c0a2d72013-11-15 15:16:36 -0800428 if self.ir_class.is_subclassof('of_bsn_stats_request'):
429 return ("", "OFBsnStatsRequest", None)
430 elif self.ir_class.is_subclassof('of_experimenter_stats_request'):
431 return ("", "OFExperimenterStatsRequest", None)
432 else:
433 return ("", "OFStatsRequest<{}>".format(re.sub(r'Request$', 'Reply', self.name)), None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800434 elif self.ir_class.is_subclassof('of_stats_reply'):
Andreas Wundsam2c0a2d72013-11-15 15:16:36 -0800435 if self.ir_class.is_subclassof('of_bsn_stats_reply'):
436 return ("", "OFBsnStatsReply", None)
437 elif self.ir_class.is_subclassof('of_experimenter_stats_reply'):
438 return ("", "OFExperimenterStatsReply", None)
439 else:
440 return ("", "OFStatsReply", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800441 elif self.ir_class.is_subclassof('of_error_msg'):
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700442 return ("", "OFErrorMsg", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800443 elif self.ir_class.is_subclassof('of_flow_mod'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700444 return ("", "OFFlowMod", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800445 elif self.ir_class.is_subclassof('of_group_mod'):
446 return ("", "OFGroupMod", None)
447 elif self.ir_class.is_subclassof('of_bsn_header'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700448 return ("", "OFBsnHeader", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800449 elif self.ir_class.is_subclassof('of_nicira_header'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700450 return ("", "OFNiciraHeader", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800451 elif self.ir_class.is_subclassof('of_experimenter'):
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700452 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700453 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700454 return ("", "Match", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800455 elif self.ir_class.is_message:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700456 return ("", "OFMessage", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800457 elif self.ir_class.is_action:
458 if self.ir_class.is_subclassof('of_action_bsn'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700459 return ("action", "OFActionBsn", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800460 elif self.ir_class.is_subclassof('of_action_nicira'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700461 return ("action", "OFActionNicira", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800462 elif self.ir_class.is_subclassof('of_action_experimenter'):
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700463 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700464 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700465 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700466 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700467 return ("", "OFBsnVport", None)
468 elif self.name == "OFOxm":
469 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700470 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800471 if self.member_by_name("value") is not None:
472 return ("oxm", "OFOxm<%s>" % self.member_by_name("value").java_type.public_type, None)
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700473 else:
474 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700475 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700476 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700477 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700478 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700479 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700480 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700481 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700482 return ("", "OFHelloElem", None)
Rich Lane26847562013-10-08 13:44:47 -0700483 elif loxi_utils.class_is_table_feature_prop(self.c_name):
484 return ("", "OFTableFeatureProp", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700485 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700486 return ("", None, None)
487
488 @property
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800489
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700490 @memoize
491 def writeable_members(self):
492 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700493
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700494 @memoize
495 def member_by_name(self, name):
496 return find(lambda m: m.name == name, self.members)
497
Andreas Wundsam27303462013-07-16 12:52:35 -0700498 @property
499 @memoize
500 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700501 return self.ir_model_members + self.virtual_members
502
503 @property
504 @memoize
505 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700506 """return a list of all members to be exposed by this interface. Corresponds to
507 the union of the members of the vesioned classes without length, fieldlength
508 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700509 all_versions = []
510 member_map = collections.OrderedDict()
511
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800512 member_version_map = {}
Andreas Wundsam27303462013-07-16 12:52:35 -0700513 for (version, of_class) in self.version_map.items():
514 for of_member in of_class.members:
515 if isinstance(of_member, OFLengthMember) or \
516 isinstance(of_member, OFFieldLengthMember) or \
517 isinstance(of_member, OFPadMember):
518 continue
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800519 java_member = JavaMember.for_of_member(self, of_member)
Andreas Wundsam27303462013-07-16 12:52:35 -0700520 if of_member.name not in member_map:
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800521 member_map[of_member.name] = java_member
522 member_version_map[of_member.name] = version
523 else:
524 existing = member_map[of_member.name]
525
526 if existing.java_type.public_type != java_member.java_type.public_type:
527 raise Exception(
528 "Error constructing interface {}: type signatures do not match up between versions.\n"
529 " Member Name: {}\n"
530 " Existing: Version={}, Java={}, IR={}\n"
531 " New: Version={}, Java={}, IR={}"
532 .format(self.name, existing.name,
533 member_version_map[of_member.name], existing.java_type.public_type, existing.member.oftype,
534 version, java_member.java_type.public_type, java_member.member.oftype)
535 )
Andreas Wundsam27303462013-07-16 12:52:35 -0700536
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700537 return tuple(m for m in member_map.values() if m.name not in model.read_blacklist[self.name])
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700538
539 @property
540 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700541 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700542 if self.name == "OFOxm":
Andreas Wundsama0981022013-10-02 18:15:06 -0700543 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700544 JavaVirtualMember(self, "value", java_type.generic_t),
545 JavaVirtualMember(self, "mask", java_type.generic_t),
546 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
547 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800548 JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype("T"))
Andreas Wundsama0981022013-10-02 18:15:06 -0700549 ]
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800550 elif self.ir_class.is_subclassof("of_oxm"):
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800551 value = find(lambda m: m.name=="value", self.ir_model_members)
552 if value:
553 field_type = java_type.make_match_field_jtype(value.java_type.public_type)
554 else:
555 field_type = java_type.make_match_field_jtype()
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700556
Andreas Wundsama0981022013-10-02 18:15:06 -0700557 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700558 JavaVirtualMember(self, "matchField", field_type),
559 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800560 JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype(value.java_type.public_type),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800561 custom_template=lambda builder: "OFOxm{}_getCanonical.java".format(".Builder" if builder else "")),
Andreas Wundsama0981022013-10-02 18:15:06 -0700562 ]
563 if not find(lambda x: x.name == "mask", self.ir_model_members):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800564 virtual_members.append(
565 JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type))
Andreas Wundsama0981022013-10-02 18:15:06 -0700566
567 if not find(lambda m: m.name == "version", self.ir_model_members):
568 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version))
569
570 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700571
572 @property
573 @memoize
574 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700575 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700576 return self.name in model.virtual_interfaces or all(ir_class.virtual for ir_class in self.version_map.values())
Andreas Wundsam27303462013-07-16 12:52:35 -0700577
578 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700579 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700580 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700581 return len(self.all_versions) == len(model.versions)
582
583 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700584 @memoize
585 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700586 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700587 return self.version_map.keys()
588
Andreas Wundsam5204de22013-07-30 11:34:45 -0700589 def has_version(self, version):
590 return version in self.version_map
591
Andreas Wundsam27303462013-07-16 12:52:35 -0700592 def versioned_class(self, version):
593 return JavaOFClass(self, version, self.version_map[version])
594
595 @property
596 @memoize
597 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700598 return [ self.versioned_class(version) for version in self.all_versions ]
599
600#######################################################################
601### (Versioned) Classes
602#######################################################################
603
604class JavaOFClass(object):
605 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700606 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700607 """
608 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700609 """
610 @param interface JavaOFInterface instance of the parent interface
611 @param version JavaOFVersion
612 @param ir_class OFClass from loxi_ir
613 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700614 self.interface = interface
615 self.ir_class = ir_class
616 self.c_name = self.ir_class.name
617 self.version = version
618 self.constant_name = self.c_name.upper().replace("OF_", "")
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800619 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.dotless_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700620 self.generated = False
621
622 @property
623 @memoize
624 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700625 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700626
627 @property
628 def name(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800629 return "%sVer%s" % (self.interface.name, self.version.dotless_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700630
631 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700632 def variable_name(self):
Andreas Wundsam781d99f2013-10-23 15:25:56 -0700633 return self.name[2].lower() + self.name[3:]
Andreas Wundsam5204de22013-07-30 11:34:45 -0700634
635 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700636 def length(self):
637 if self.is_fixed_length:
638 return self.min_length
639 else:
640 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
641
642 @property
643 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700644 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800645 return self.ir_class.base_length
Andreas Wundsam27303462013-07-16 12:52:35 -0700646
647 @property
648 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700649 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800650 return self.ir_class.is_fixed_length and not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700651
652 def all_properties(self):
653 return self.interface.members
654
Andreas Wundsam27303462013-07-16 12:52:35 -0700655 @property
656 @memoize
657 def data_members(self):
658 return [ prop for prop in self.members if prop.is_data ]
659
660 @property
661 @memoize
662 def fixed_value_members(self):
663 return [ prop for prop in self.members if prop.is_fixed_value ]
664
665 @property
666 @memoize
667 def public_members(self):
668 return [ prop for prop in self.members if prop.is_public ]
669
670 @property
671 @memoize
672 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700673 return self.ir_model_members + self.virtual_members
674
675 @property
Andreas Wundsama0981022013-10-02 18:15:06 -0700676 @memoize
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700677 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700678 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700679 return tuple(members)
680
681 @property
682 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700683 virtual_members = []
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800684 if self.ir_class.is_subclassof("of_oxm"):
685 value_member = find(lambda m: m.name, self.ir_model_members)
686 if value_member:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700687 oxm_entry = model.oxm_map[self.interface.name]
Andreas Wundsama0981022013-10-02 18:15:06 -0700688 virtual_members += [
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800689 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(value_member.java_type.public_type), "MatchField.%s" % oxm_entry.value),
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700690 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800691 ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700692 else:
Andreas Wundsama0981022013-10-02 18:15:06 -0700693 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700694 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
695 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800696 ]
Andreas Wundsama0981022013-10-02 18:15:06 -0700697 if not find(lambda m: m.name == "version", self.ir_model_members):
698 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version, "OFVersion.%s" % self.version.constant_version))
699
700 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700701
Andreas Wundsam661a2222013-11-05 17:18:59 -0800702 @memoize
703 def member_by_name(self, name):
704 return find(lambda m: m.name == name, self.members)
705
Andreas Wundsam27303462013-07-16 12:52:35 -0700706 def all_versions(self):
707 return [ JavaOFVersion(int_version)
708 for int_version in of_g.unified[self.c_name]
709 if int_version != 'union' and int_version != 'object_id' ]
710
711 def version_is_inherited(self, version):
712 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
713
714 def inherited_from(self, version):
715 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
716
717 @property
718 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700719 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
720
721 @property
722 def discriminator(self):
723 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700724
725 @property
726 def is_extension(self):
727 return type_maps.message_is_extension(self.c_name, -1)
728
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700729 @property
730 def align(self):
731 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
732
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700733 @property
Andreas Wundsam5da68512013-10-22 22:18:00 -0700734 def length_includes_align(self):
735 return self.ir_class.params['length_includes_align'] == "True" if 'length_includes_align' in self.ir_class.params else False
736
737 @property
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700738 @memoize
739 def superclass(self):
740 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
741
742 @property
743 @memoize
744 def subclasses(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800745 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass
746 and c.ir_class.superclass.name == self.c_name ]
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700747
Andreas Wundsam27303462013-07-16 12:52:35 -0700748#######################################################################
749### Member
750#######################################################################
751
752
753class JavaMember(object):
754 """ Models a property (member) of an openflow class. """
755 def __init__(self, msg, name, java_type, member):
756 self.msg = msg
757 self.name = name
758 self.java_type = java_type
759 self.member = member
760 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700761
762 @property
763 def title_name(self):
764 return self.name[0].upper() + self.name[1:]
765
766 @property
767 def constant_name(self):
768 return self.c_name.upper()
769
770 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700771 def getter_name(self):
772 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
773
774 @property
775 def setter_name(self):
776 return "set" + self.title_name
777
778 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700779 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700780 if self.is_fixed_value:
781 return self.constant_name
782 else:
783 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700784
785 @property
786 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700787 if self.is_fixed_value:
788 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700789 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700790 default = self.java_type.default_op(self.msg.version)
791 if default == "null" and not self.is_nullable:
792 return None
793 else:
794 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700795
796 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700797 def enum_value(self):
798 if self.name == "version":
799 return "OFVersion.%s" % self.msg.version.constant_version
800
801 java_type = self.java_type.public_type;
802 try:
803 global model
804 enum = model.enum_by_name(java_type)
805 entry = enum.entry_by_version_value(self.msg.version, self.value)
806 return "%s.%s" % ( enum.name, entry.name)
807 except KeyError, e:
Andreas Wundsamaa8a9182013-11-19 09:45:01 -0800808 logger.debug("No enum found", e)
Andreas Wundsam27303462013-07-16 12:52:35 -0700809 return self.value
810
811 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700812 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700813 return isinstance(self.member, OFPadMember)
814
815 def is_type_value(self, version=None):
816 if(version==None):
817 return any(self.is_type_value(version) for version in self.msg.all_versions)
818 try:
819 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
820 except:
821 return False
822
823 @property
824 def is_field_length_value(self):
825 return isinstance(self.member, OFFieldLengthMember)
826
827 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700828 def is_discriminator(self):
829 return isinstance(self.member, OFDiscriminatorMember)
830
831 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700832 def is_length_value(self):
833 return isinstance(self.member, OFLengthMember)
834
835 @property
836 def is_public(self):
837 return not (self.is_pad or self.is_length_value)
838
839 @property
840 def is_data(self):
841 return isinstance(self.member, OFDataMember) and self.name != "version"
842
843 @property
844 def is_fixed_value(self):
845 return hasattr(self.member, "value") or self.name == "version" \
846 or ( self.name == "length" and self.msg.is_fixed_length) \
847 or ( self.name == "len" and self.msg.is_fixed_length)
848
849 @property
850 def value(self):
851 if self.name == "version":
852 return self.msg.version.int_version
853 elif self.name == "length" or self.name == "len":
854 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700855 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700856 return self.java_type.format_value(self.member.value)
857
858 @property
859 def priv_value(self):
860 if self.name == "version":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700861 return self.java_type.format_value(self.msg.version.int_version, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700862 elif self.name == "length" or self.name == "len":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700863 return self.java_type.format_value(self.msg.length, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700864 else:
865 return self.java_type.format_value(self.member.value, pub_type=False)
866
Andreas Wundsam27303462013-07-16 12:52:35 -0700867
868 @property
869 def is_writeable(self):
870 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
871
872 def get_type_value_info(self, version):
873 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700874
875 @property
876 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700877 if hasattr(self.member, "length"):
878 return self.member.length
879 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700880 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700881 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700882
883 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700884 def for_of_member(java_class, member):
885 if isinstance(member, OFPadMember):
886 return JavaMember(None, "", None, member)
887 else:
888 if member.name == 'len':
889 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700890 elif member.name == 'value_mask':
891 name = 'mask'
Andreas Wundsamacd57d52013-10-18 17:35:01 -0700892 elif member.name == 'group_id':
893 name = 'group'
Andreas Wundsam27303462013-07-16 12:52:35 -0700894 else:
895 name = java_type.name_c_to_camel(member.name)
896 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
897 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700898
899 @property
900 def is_universal(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800901 for version, ir_class in self.msg.ir_class.version_classes.items():
902 if not ir_class.member_by_name(self.member.name):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700903 return False
904 return True
905
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700906 @property
907 def is_virtual(self):
908 return False
909
Andreas Wundsam27303462013-07-16 12:52:35 -0700910 def __hash__(self):
911 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700912
Andreas Wundsam27303462013-07-16 12:52:35 -0700913 def __eq__(self, other):
914 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700915 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700916 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700917
Andreas Wundsamf1949682013-09-23 14:48:31 -0700918 @property
919 def is_nullable(self):
920 return self.name in model.nullable_map[self.msg.name]
921
922
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700923class JavaVirtualMember(JavaMember):
924 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
Andreas Wundsam4b8661f2013-11-05 17:17:28 -0800925 def __init__(self, msg, name, java_type, value=None, custom_template=None):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700926 JavaMember.__init__(self, msg, name, java_type, member=None)
927 self._value = value
Andreas Wundsam4b8661f2013-11-05 17:17:28 -0800928 self.custom_template = custom_template
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700929
930 @property
931 def is_fixed_value(self):
932 return True
933
934 @property
935 def value(self):
936 return self._value
937
938 @property
939 def priv_value(self):
940 return self._value
941
942
943 @property
944 def is_universal(self):
945 return True
946
947 @property
948 def is_virtual(self):
949 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700950
951#######################################################################
952### Unit Test
953#######################################################################
954
Yotam Harchol466b3212013-08-15 12:14:46 -0700955class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700956 def __init__(self, java_class):
957 self.java_class = java_class
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800958 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.dotless_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700959 name=java_class.c_name[3:])
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800960 glob_file_name = "of{version}/{name}__*.data".format(version=java_class.version.dotless_version,
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -0700961 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700962 test_class_name = self.java_class.name + "Test"
963 self.test_units = []
964 if test_data.exists(first_data_file_name):
965 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -0700966
Yotam Harchol466b3212013-08-15 12:14:46 -0700967 i = 1
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -0700968 for f in test_data.glob(glob_file_name):
969 m = re.match(".*__(.*).data", f)
970 if m:
971 suffix = java_type.name_c_to_caps_camel(m.group(1))
972 else:
973 suffix = str(i)
974 i += 1
975 test_class_name = self.java_class.name + suffix + "Test"
976 self.test_units.append(JavaUnitTest(java_class, f, test_class_name))
Andreas Wundsamf1949682013-09-23 14:48:31 -0700977
Yotam Harchol466b3212013-08-15 12:14:46 -0700978 @property
979 def package(self):
980 return self.java_class.package
981
982 @property
983 def has_test_data(self):
984 return len(self.test_units) > 0
985
986 @property
987 def length(self):
988 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -0700989
Yotam Harchol466b3212013-08-15 12:14:46 -0700990 def get_test_unit(self, i):
991 return self.test_units[i]
992
993
994class JavaUnitTest(object):
995 def __init__(self, java_class, file_name=None, test_class_name=None):
996 self.java_class = java_class
997 if file_name is None:
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800998 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.dotless_version,
Yotam Harchol466b3212013-08-15 12:14:46 -0700999 name=java_class.c_name[3:])
1000 else:
1001 self.data_file_name = file_name
1002 if test_class_name is None:
1003 self.test_class_name = self.java_class.name + "Test"
1004 else:
1005 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001006
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001007 @property
1008 def package(self):
1009 return self.java_class.package
1010
1011 @property
1012 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001013 return self.test_class_name
Yotam Harchol595c6442013-09-27 16:29:08 -07001014
1015 @property
1016 def interface(self):
1017 return self.java_class.interface
1018
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001019 @property
1020 def has_test_data(self):
1021 return test_data.exists(self.data_file_name)
1022
1023 @property
1024 @memoize
1025 def test_data(self):
1026 return test_data.read(self.data_file_name)
1027
1028
Andreas Wundsam27303462013-07-16 12:52:35 -07001029#######################################################################
1030### Enums
1031#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001032
Andreas Wundsam27303462013-07-16 12:52:35 -07001033class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001034 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001035 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001036
Rob Vaterlausfeee3712013-09-30 11:24:19 -07001037 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001038
Andreas Wundsam27303462013-07-16 12:52:35 -07001039 # Port_features has constants that start with digits
1040 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001041
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001042 self.version_enums = version_enum_map
1043
1044 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1045 for version, ir_enum in version_enum_map.items():
1046 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001047 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1048
Andreas Wundsam27303462013-07-16 12:52:35 -07001049 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001050 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001051
1052 self.entries = [ e for e in self.entries if e.name not in model.enum_entry_blacklist[self.name] ]
Yotam Harchol791e4882013-09-05 16:32:56 -07001053 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001054
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001055 self.metadata = model.enum_metadata_map[self.name]
1056
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001057 def wire_type(self, version):
1058 ir_enum = self.version_enums[version]
1059 if "wire_type" in ir_enum.params:
1060 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1061 else:
1062 return java_type.u8
1063
1064 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001065 @memoize
1066 def is_bitmask(self):
1067 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1068
1069 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001070 def versions(self):
1071 return self.version_enums.keys()
1072
Andreas Wundsam27303462013-07-16 12:52:35 -07001073 @memoize
1074 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001075 res = find(lambda e: e.name == name, self.entries)
1076 if res:
1077 return res
1078 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001079 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1080
1081 @memoize
1082 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001083 res = find(lambda e: e.c_name == name, self.entries)
1084 if res:
1085 return res
1086 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001087 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1088
1089 @memoize
1090 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001091 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1092 if res:
1093 return res
1094 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001095 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1096
1097# values: Map JavaVersion->Value
1098class JavaEnumEntry(object):
1099 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001100 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001101 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1102 self.values = values
1103
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001104 @property
1105 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001106 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001107
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001108 def has_value(self, version):
1109 return version in self.values
1110
Andreas Wundsam27303462013-07-16 12:52:35 -07001111 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001112 return self.values[version]
1113
1114 def format_value(self, version):
1115 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001116 return res
1117
Andreas Wundsam27303462013-07-16 12:52:35 -07001118 def all_values(self, versions, not_present=None):
1119 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001120
1121 @property
1122 @memoize
1123 def masked_enum_group(self):
1124 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1125 return group
1126
1127 @property
1128 @memoize
1129 def is_mask(self):
1130 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])