blob: 8f5434e3c82c979997a13eefe79347ceb657c2b9 [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')),
Rich Lanef33f32f2013-11-18 15:49:54 -080068 OFExperimenterStatsReply=set(('data','subtype')),
69 OFInstructionExperimenter=set(('data',)))
Andreas Wundsamf1949682013-09-23 14:48:31 -070070 # map: $java_type -> set(java_name_property)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070071 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 -070072 # interfaces that are virtual
Andreas Wundsam001b1822013-08-02 22:25:55 -070073 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070074
Andreas Wundsamf1949682013-09-23 14:48:31 -070075 # Registry of nullable properties:
76 # ${java_class_name} -> set(${java_property_name})
77 nullable_map = defaultdict(lambda: set(),
78 )
79
80 # represents a subgroup of a bitmask enum that is actualy a normal enumerable within a masked part of the enum
81 # e.g., the flags STP.* in OF1.0 port state are bit mask entries, but instead enumerables according to the mask "STP_MASK"
82 # name: a name for the group
83 # mask: java name of the enum entry that defines the mask
84 # members: set of names of the members of the group
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -070085 MaskedEnumGroup = namedtuple("MaskedEnumGroup", ("name", "mask", "members"))
86
Andreas Wundsamf1949682013-09-23 14:48:31 -070087 # registry of MaskedEnumGroups (see above).
88 # map: ${java_enum_name}: tuple(MaskedEnumGroup)
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -070089 masked_enum_groups = defaultdict(lambda: (),
Andreas Wundsamaebe5182013-09-24 13:01:07 -070090 OFPortState = (MaskedEnumGroup("stp_flags", mask="STP_MASK", members=set(("STP_LISTEN", "STP_LEARN", "STP_FORWARD", "STP_BLOCK"))), ),
91 OFConfigFlags = (
92 MaskedEnumGroup("frag_flags", mask="FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
Andreas Wundsam376cef52013-09-24 13:52:18 -070093 ),
94 OFTableConfig = (
95 MaskedEnumGroup("table_miss_flags", mask="TABLE_MISS_MASK", members=set(("TABLE_MISS_CONTROLLER", "TABLE_MISS_CONTINUE", "TABLE_MISS_DROP"))),
96 ),
Andreas Wundsam057540b2013-11-19 16:51:36 -080097 OFGetConfigReply = (
98 MaskedEnumGroup("flags", mask="OFP_FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
99 ),
100 OFSetConfig = (
101 MaskedEnumGroup("flags", mask="OFP_FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
102 ),
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700103 )
104
Andreas Wundsamf1949682013-09-23 14:48:31 -0700105 # represents a metadata property associated with an EnumClass
106 # name:
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700107 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700108 """
109 represents a metadata property associated with an Enum Class
110 @param name name of metadata property
111 @param type java_type instance describing the type
112 @value: Generator function f(entry) that generates the value
113 """
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700114 @property
115 def variable_name(self):
116 return self.name[0].lower() + self.name[1:]
117
118 @property
119 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700120 prefix = "is" if self.type == java_type.boolean else "get"
121 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700122
Andreas Wundsamf1949682013-09-23 14:48:31 -0700123 """ Metadata container. """
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700124 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
125
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700126 def gen_port_speed(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700127 """ Generator function for OFortFeatures.PortSpeed"""
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700128 splits = enum_entry.name.split("_")
129 if len(splits)>=2:
130 m = re.match(r'\d+[MGTP]B', splits[1])
131 if m:
132 return "PortSpeed.SPEED_{}".format(splits[1])
133 return "PortSpeed.SPEED_NONE";
134
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700135 def gen_stp_state(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700136 """ Generator function for OFPortState.StpState"""
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700137 splits = enum_entry.name.split("_")
138 if len(splits)>=1:
139 if splits[0] == "STP":
140 return "true"
141 return "false"
142
Andreas Wundsamf1949682013-09-23 14:48:31 -0700143 # registry for metadata properties for enums
144 # map: ${java_enum_name}: OFEnumMetadata
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700145 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
Rob Vaterlausa049dee2013-09-18 16:18:37 -0700146 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
147 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700148 )
149
Andreas Wundsam27303462013-07-16 12:52:35 -0700150 @property
151 @memoize
152 def versions(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800153 return OrderedSet( JavaOFVersion(ir_version) for ir_version in OFVersions.target_versions)
Andreas Wundsam27303462013-07-16 12:52:35 -0700154
155 @property
156 @memoize
157 def interfaces(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800158 interfaces = [ JavaOFInterface(ir_class) for ir_class in loxi_globals.unified.classes ]
Andreas Wundsambe168f72013-08-03 22:49:35 -0700159 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
160
Andreas Wundsam27303462013-07-16 12:52:35 -0700161 return interfaces
162
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700163 @memoize
164 def interface_by_name(self, name):
165 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
166
Andreas Wundsam27303462013-07-16 12:52:35 -0700167 @property
168 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700169 def all_classes(self):
170 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
171
172 @property
173 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700174 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700175 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700176
177 for version in self.versions:
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800178 logger.info("version: {}".format(version.ir_version))
179 of_protocol = loxi_globals.ir[version.ir_version]
Andreas Wundsam27303462013-07-16 12:52:35 -0700180 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700181 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700182
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700183 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
184 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700185
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700186 # inelegant - need java name here
187 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700188 return enums
189
190 @memoize
191 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700192 res = find(lambda e: e.name == name, self.enums)
193 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700194 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700195 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700196
Andreas Wundsam5204de22013-07-30 11:34:45 -0700197 @property
198 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700199 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700200 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700201
202 factories = OrderedDict()
203
204 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
205 for base_class in sub_factory_classes:
206 package = base_class[2:].lower()
207 remove_prefix = base_class[2].lower() + base_class[3:]
208
209 # HACK need to have a better way to deal with parameterized base classes
210 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
211
212 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700213 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 -0700214
215 factories[""] = OFFactory(
216 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700217 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700218 remove_prefix="",
219 members=[], base_class="OFMessage", sub_factories=OrderedDict(
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700220 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ),
221 xid_generator=True)
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700222
223 for i in self.interfaces:
224 for n, factory in factories.items():
225 if n == "":
226 factory.members.append(i)
227 break
228 else:
229 super_class = self.interface_by_name(n)
230 if i.is_instance_of(super_class):
231 factory.members.append(i)
232 break
233 return factories.values()
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800234
Yotam Harchol595c6442013-09-27 16:29:08 -0700235 @memoize
236 def factory_of(self, interface):
237 for factory in self.of_factories:
238 if interface in factory.members:
239 return factory
240 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700241
242 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700243 """ return wether or not to generate implementation class clazz.
244 Now true for everything except OFTableModVer10.
245 @param clazz JavaOFClass instance
246 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700247 if clazz.interface.name.startswith("OFMatchV"):
248 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700249 elif clazz.name == "OFTableModVer10":
250 # tablemod ver 10 is a hack and has no oftype defined
251 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700252 if loxi_utils.class_is_message(clazz.interface.c_name):
253 return True
254 if loxi_utils.class_is_oxm(clazz.interface.c_name):
255 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700256 if loxi_utils.class_is_action(clazz.interface.c_name):
257 return True
258 if loxi_utils.class_is_instruction(clazz.interface.c_name):
259 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700260 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700261 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700262
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800263 @property
264 @memoize
265 def oxm_map(self):
266 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
267 return OrderedDict( (oxm.name, OxmMapEntry(type_name=oxm.member_by_name("value").java_type.public_type,
268 value=re.sub(r'^of_oxm_', r'', re.sub(r'_masked$', r'', oxm.ir_class.name)).upper(),
269 masked=oxm.ir_class.name.endswith("_masked")))
270 for oxm in self.interfaces if oxm.ir_class.is_subclassof("of_oxm") )
Andreas Wundsam5204de22013-07-30 11:34:45 -0700271
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700272class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories", "xid_generator"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700273 @property
274 def factory_classes(self):
275 return [ OFFactoryClass(
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800276 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.dotless_version),
277 name="{}Ver{}".format(self.name, version.dotless_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700278 interface=self,
279 version=version
280 ) for version in model.versions ]
281
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700282 def method_name(self, member, builder=True):
283 n = member.variable_name
284 if n.startswith(self.remove_prefix):
285 n = n[len(self.remove_prefix):]
286 n = n[0].lower() + n[1:]
287 if builder:
288 return "build" + n[0].upper() + n[1:]
289 else:
290 return n
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800291
Yotam Harchol595c6442013-09-27 16:29:08 -0700292 def of_version(self, version):
293 for fc in self.factory_classes:
294 if fc.version == version:
295 return fc
296 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700297
298OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700299class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
300 @property
301 def base_class(self):
302 return self.interface.base_class
303
304 @property
305 def versioned_base_class(self):
306 base_class_interface = model.interface_by_name(self.interface.base_class)
307 if base_class_interface and base_class_interface.has_version(self.version):
308 return base_class_interface.versioned_class(self.version)
309 else:
310 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700311
Andreas Wundsam27303462013-07-16 12:52:35 -0700312model = JavaModel()
313
314#######################################################################
315### OFVersion
316#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700317
318class JavaOFVersion(object):
319 """ Models a version of OpenFlow. contains methods to convert the internal
320 Loxi version to a java constant / a string """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800321 def __init__(self, ir_version):
322 assert isinstance(ir_version, OFVersion)
323 self.ir_version = ir_version
324 self.int_version = self.ir_version.wire_version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700325
326 @property
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800327 def dotless_version(self):
328 return self.ir_version.version.replace(".", "")
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700329
330 @property
331 def constant_version(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800332 return "OF_" + self.dotless_version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700333
Andreas Wundsam27303462013-07-16 12:52:35 -0700334 def __repr__(self):
335 return "JavaOFVersion(%d)" % self.int_version
336
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700337 def __str__(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800338 return self.ir_version.version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700339
Andreas Wundsam27303462013-07-16 12:52:35 -0700340 def __hash__(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800341 return hash(self.ir_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700342
343 def __eq__(self, other):
344 if other is None or type(self) != type(other):
345 return False
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800346 return (self.ir_version,) == (other.ir_version,)
Andreas Wundsam27303462013-07-16 12:52:35 -0700347
348#######################################################################
349### Interface
350#######################################################################
351
352class JavaOFInterface(object):
353 """ Models an OpenFlow Message class for the purpose of the java class.
354 Version agnostic, in contrast to the loxi_ir python model.
355 """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800356 def __init__(self, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700357 """"
358 @param c_name: loxi style name (e.g., of_flow_add)
359 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
360 """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800361 self.ir_class = ir_class
362 self.c_name = ir_class.name
363 self.version_map = { JavaOFVersion(v): c for v,c in ir_class.version_classes.items() }
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700364 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800365 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 -0700366 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700367 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700368 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700369 # name for use in constants: FLOW_ADD
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800370 self.constant_name = self.c_name.upper().replace("OF_", "")
Andreas Wundsam27303462013-07-16 12:52:35 -0700371
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700372 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700373 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700374 if self.name != parent_interface:
375 self.parent_interface = parent_interface
376 else:
377 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700378
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700379 @property
380 @memoize
381 def all_parent_interfaces(self):
382 return [ "OFObject" ] + \
383 ([ self.parent_interface ] if self.parent_interface else [] )+ \
384 self.additional_parent_interfaces
385 @property
386 @memoize
387 def additional_parent_interfaces(self):
388 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
389 m = re.match(r'(.*)Request$', self.name)
390 if m:
391 reply_name = m.group(1) + "Reply"
392 if model.interface_by_name(reply_name):
393 return ["OFRequest<%s>" % reply_name ]
394 return []
395
396
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700397 def is_instance_of(self, other_class):
398 if self == other_class:
399 return True
400 parent = self.super_class
401 if parent is None:
402 return False
403 else:
404 return parent.is_instance_of(other_class)
405
406 @property
407 def super_class(self):
408 if not self.parent_interface:
409 return None
410 else:
411 return model.interface_by_name(self.parent_interface)
412
413
414 def inherited_declaration(self, type_spec="?"):
415 if self.type_annotation:
416 return "%s<%s>" % (self.name, type_spec)
417 else:
418 return "%s" % self.name
419
420 @property
421 def type_variable(self):
422 if self.type_annotation:
423 return "<T>"
424 else:
425 return "";
426
Andreas Wundsam27303462013-07-16 12:52:35 -0700427 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700428 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
429 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
430 # model (note, that the loxi model is on versioned classes). Should check/infer the
431 # inheritance information from the versioned lox_ir classes.
Andreas Wundsamd6b0cb02013-09-28 18:55:56 -0700432 if re.match(r'OFStatsRequest$', self.name):
433 return ("", "OFMessage", "T extends OFStatsReply")
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800434 elif self.ir_class.is_subclassof('of_stats_request'):
Andreas Wundsam2c0a2d72013-11-15 15:16:36 -0800435 if self.ir_class.is_subclassof('of_bsn_stats_request'):
436 return ("", "OFBsnStatsRequest", None)
437 elif self.ir_class.is_subclassof('of_experimenter_stats_request'):
438 return ("", "OFExperimenterStatsRequest", None)
439 else:
440 return ("", "OFStatsRequest<{}>".format(re.sub(r'Request$', 'Reply', self.name)), None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800441 elif self.ir_class.is_subclassof('of_stats_reply'):
Andreas Wundsam2c0a2d72013-11-15 15:16:36 -0800442 if self.ir_class.is_subclassof('of_bsn_stats_reply'):
443 return ("", "OFBsnStatsReply", None)
444 elif self.ir_class.is_subclassof('of_experimenter_stats_reply'):
445 return ("", "OFExperimenterStatsReply", None)
446 else:
447 return ("", "OFStatsReply", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800448 elif self.ir_class.is_subclassof('of_error_msg'):
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700449 return ("", "OFErrorMsg", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800450 elif self.ir_class.is_subclassof('of_flow_mod'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700451 return ("", "OFFlowMod", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800452 elif self.ir_class.is_subclassof('of_group_mod'):
453 return ("", "OFGroupMod", None)
454 elif self.ir_class.is_subclassof('of_bsn_header'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700455 return ("", "OFBsnHeader", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800456 elif self.ir_class.is_subclassof('of_nicira_header'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700457 return ("", "OFNiciraHeader", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800458 elif self.ir_class.is_subclassof('of_experimenter'):
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700459 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700460 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700461 return ("", "Match", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800462 elif self.ir_class.is_message:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700463 return ("", "OFMessage", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800464 elif self.ir_class.is_action:
465 if self.ir_class.is_subclassof('of_action_bsn'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700466 return ("action", "OFActionBsn", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800467 elif self.ir_class.is_subclassof('of_action_nicira'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700468 return ("action", "OFActionNicira", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800469 elif self.ir_class.is_subclassof('of_action_experimenter'):
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700470 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700471 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700472 return ("action", "OFAction", None)
Rich Lanef33f32f2013-11-18 15:49:54 -0800473 elif self.ir_class.is_instruction:
474 if self.ir_class.is_subclassof('of_instruction_bsn'):
475 return ("instruction", "OFInstructionBsn", None)
476 elif self.ir_class.is_subclassof('of_instruction_experimenter'):
477 return ("instruction", "OFInstructionExperimenter", None)
478 else:
479 return ("instruction", "OFInstruction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700480 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700481 return ("", "OFBsnVport", None)
482 elif self.name == "OFOxm":
483 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700484 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800485 if self.member_by_name("value") is not None:
486 return ("oxm", "OFOxm<%s>" % self.member_by_name("value").java_type.public_type, None)
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700487 else:
488 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700489 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700490 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700491 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700492 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700493 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700494 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700495 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700496 return ("", "OFHelloElem", None)
Rich Lane26847562013-10-08 13:44:47 -0700497 elif loxi_utils.class_is_table_feature_prop(self.c_name):
498 return ("", "OFTableFeatureProp", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700499 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700500 return ("", None, None)
501
502 @property
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800503
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700504 @memoize
505 def writeable_members(self):
506 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700507
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700508 @memoize
509 def member_by_name(self, name):
510 return find(lambda m: m.name == name, self.members)
511
Andreas Wundsam27303462013-07-16 12:52:35 -0700512 @property
513 @memoize
514 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700515 return self.ir_model_members + self.virtual_members
516
517 @property
518 @memoize
519 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700520 """return a list of all members to be exposed by this interface. Corresponds to
521 the union of the members of the vesioned classes without length, fieldlength
522 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700523 all_versions = []
524 member_map = collections.OrderedDict()
525
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800526 member_version_map = {}
Andreas Wundsam27303462013-07-16 12:52:35 -0700527 for (version, of_class) in self.version_map.items():
528 for of_member in of_class.members:
529 if isinstance(of_member, OFLengthMember) or \
530 isinstance(of_member, OFFieldLengthMember) or \
531 isinstance(of_member, OFPadMember):
532 continue
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800533 java_member = JavaMember.for_of_member(self, of_member)
Andreas Wundsam27303462013-07-16 12:52:35 -0700534 if of_member.name not in member_map:
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800535 member_map[of_member.name] = java_member
536 member_version_map[of_member.name] = version
537 else:
538 existing = member_map[of_member.name]
539
540 if existing.java_type.public_type != java_member.java_type.public_type:
541 raise Exception(
542 "Error constructing interface {}: type signatures do not match up between versions.\n"
543 " Member Name: {}\n"
544 " Existing: Version={}, Java={}, IR={}\n"
545 " New: Version={}, Java={}, IR={}"
546 .format(self.name, existing.name,
547 member_version_map[of_member.name], existing.java_type.public_type, existing.member.oftype,
548 version, java_member.java_type.public_type, java_member.member.oftype)
549 )
Andreas Wundsam27303462013-07-16 12:52:35 -0700550
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700551 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 -0700552
553 @property
554 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700555 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700556 if self.name == "OFOxm":
Andreas Wundsama0981022013-10-02 18:15:06 -0700557 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700558 JavaVirtualMember(self, "value", java_type.generic_t),
559 JavaVirtualMember(self, "mask", java_type.generic_t),
560 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
561 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800562 JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype("T"))
Andreas Wundsama0981022013-10-02 18:15:06 -0700563 ]
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800564 elif self.ir_class.is_subclassof("of_oxm"):
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800565 value = find(lambda m: m.name=="value", self.ir_model_members)
566 if value:
567 field_type = java_type.make_match_field_jtype(value.java_type.public_type)
568 else:
569 field_type = java_type.make_match_field_jtype()
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700570
Andreas Wundsama0981022013-10-02 18:15:06 -0700571 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700572 JavaVirtualMember(self, "matchField", field_type),
573 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800574 JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype(value.java_type.public_type),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800575 custom_template=lambda builder: "OFOxm{}_getCanonical.java".format(".Builder" if builder else "")),
Andreas Wundsama0981022013-10-02 18:15:06 -0700576 ]
577 if not find(lambda x: x.name == "mask", self.ir_model_members):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800578 virtual_members.append(
579 JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type))
Andreas Wundsama0981022013-10-02 18:15:06 -0700580
581 if not find(lambda m: m.name == "version", self.ir_model_members):
582 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version))
583
584 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700585
586 @property
587 @memoize
588 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700589 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700590 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 -0700591
592 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700593 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700594 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700595 return len(self.all_versions) == len(model.versions)
596
597 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700598 @memoize
599 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700600 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700601 return self.version_map.keys()
602
Andreas Wundsam5204de22013-07-30 11:34:45 -0700603 def has_version(self, version):
604 return version in self.version_map
605
Andreas Wundsam27303462013-07-16 12:52:35 -0700606 def versioned_class(self, version):
607 return JavaOFClass(self, version, self.version_map[version])
608
609 @property
610 @memoize
611 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700612 return [ self.versioned_class(version) for version in self.all_versions ]
613
614#######################################################################
615### (Versioned) Classes
616#######################################################################
617
618class JavaOFClass(object):
619 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700620 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700621 """
622 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700623 """
624 @param interface JavaOFInterface instance of the parent interface
625 @param version JavaOFVersion
626 @param ir_class OFClass from loxi_ir
627 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700628 self.interface = interface
629 self.ir_class = ir_class
630 self.c_name = self.ir_class.name
631 self.version = version
632 self.constant_name = self.c_name.upper().replace("OF_", "")
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800633 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.dotless_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700634 self.generated = False
635
636 @property
637 @memoize
638 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700639 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700640
641 @property
642 def name(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800643 return "%sVer%s" % (self.interface.name, self.version.dotless_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700644
645 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700646 def variable_name(self):
Andreas Wundsam781d99f2013-10-23 15:25:56 -0700647 return self.name[2].lower() + self.name[3:]
Andreas Wundsam5204de22013-07-30 11:34:45 -0700648
649 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700650 def length(self):
651 if self.is_fixed_length:
652 return self.min_length
653 else:
654 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
655
656 @property
657 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700658 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800659 return self.ir_class.base_length
Andreas Wundsam27303462013-07-16 12:52:35 -0700660
661 @property
662 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700663 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800664 return self.ir_class.is_fixed_length and not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700665
666 def all_properties(self):
667 return self.interface.members
668
Andreas Wundsam27303462013-07-16 12:52:35 -0700669 @property
670 @memoize
671 def data_members(self):
672 return [ prop for prop in self.members if prop.is_data ]
673
674 @property
675 @memoize
676 def fixed_value_members(self):
677 return [ prop for prop in self.members if prop.is_fixed_value ]
678
679 @property
680 @memoize
681 def public_members(self):
682 return [ prop for prop in self.members if prop.is_public ]
683
684 @property
685 @memoize
686 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700687 return self.ir_model_members + self.virtual_members
688
689 @property
Andreas Wundsama0981022013-10-02 18:15:06 -0700690 @memoize
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700691 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700692 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700693 return tuple(members)
694
695 @property
696 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700697 virtual_members = []
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800698 if self.ir_class.is_subclassof("of_oxm"):
699 value_member = find(lambda m: m.name, self.ir_model_members)
700 if value_member:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700701 oxm_entry = model.oxm_map[self.interface.name]
Andreas Wundsama0981022013-10-02 18:15:06 -0700702 virtual_members += [
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800703 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 -0700704 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800705 ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700706 else:
Andreas Wundsama0981022013-10-02 18:15:06 -0700707 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700708 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
709 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800710 ]
Andreas Wundsama0981022013-10-02 18:15:06 -0700711 if not find(lambda m: m.name == "version", self.ir_model_members):
712 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version, "OFVersion.%s" % self.version.constant_version))
713
714 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700715
Andreas Wundsam661a2222013-11-05 17:18:59 -0800716 @memoize
717 def member_by_name(self, name):
718 return find(lambda m: m.name == name, self.members)
719
Andreas Wundsam27303462013-07-16 12:52:35 -0700720 def all_versions(self):
721 return [ JavaOFVersion(int_version)
722 for int_version in of_g.unified[self.c_name]
723 if int_version != 'union' and int_version != 'object_id' ]
724
725 def version_is_inherited(self, version):
726 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
727
728 def inherited_from(self, version):
729 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
730
731 @property
732 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700733 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
734
735 @property
736 def discriminator(self):
737 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700738
739 @property
740 def is_extension(self):
741 return type_maps.message_is_extension(self.c_name, -1)
742
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700743 @property
744 def align(self):
745 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
746
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700747 @property
Andreas Wundsam5da68512013-10-22 22:18:00 -0700748 def length_includes_align(self):
749 return self.ir_class.params['length_includes_align'] == "True" if 'length_includes_align' in self.ir_class.params else False
750
751 @property
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700752 @memoize
753 def superclass(self):
754 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
755
756 @property
757 @memoize
758 def subclasses(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800759 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass
760 and c.ir_class.superclass.name == self.c_name ]
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700761
Andreas Wundsam27303462013-07-16 12:52:35 -0700762#######################################################################
763### Member
764#######################################################################
765
766
767class JavaMember(object):
768 """ Models a property (member) of an openflow class. """
769 def __init__(self, msg, name, java_type, member):
770 self.msg = msg
771 self.name = name
772 self.java_type = java_type
773 self.member = member
774 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700775
776 @property
777 def title_name(self):
778 return self.name[0].upper() + self.name[1:]
779
780 @property
781 def constant_name(self):
782 return self.c_name.upper()
783
784 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700785 def getter_name(self):
786 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
787
788 @property
789 def setter_name(self):
790 return "set" + self.title_name
791
792 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700793 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700794 if self.is_fixed_value:
795 return self.constant_name
796 else:
797 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700798
799 @property
800 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700801 if self.is_fixed_value:
802 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700803 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700804 default = self.java_type.default_op(self.msg.version)
805 if default == "null" and not self.is_nullable:
806 return None
807 else:
808 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700809
810 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700811 def enum_value(self):
812 if self.name == "version":
813 return "OFVersion.%s" % self.msg.version.constant_version
814
815 java_type = self.java_type.public_type;
816 try:
817 global model
818 enum = model.enum_by_name(java_type)
819 entry = enum.entry_by_version_value(self.msg.version, self.value)
820 return "%s.%s" % ( enum.name, entry.name)
821 except KeyError, e:
Andreas Wundsamaa8a9182013-11-19 09:45:01 -0800822 logger.debug("No enum found", e)
Andreas Wundsam27303462013-07-16 12:52:35 -0700823 return self.value
824
825 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700826 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700827 return isinstance(self.member, OFPadMember)
828
829 def is_type_value(self, version=None):
830 if(version==None):
831 return any(self.is_type_value(version) for version in self.msg.all_versions)
832 try:
833 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
834 except:
835 return False
836
837 @property
838 def is_field_length_value(self):
839 return isinstance(self.member, OFFieldLengthMember)
840
841 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700842 def is_discriminator(self):
843 return isinstance(self.member, OFDiscriminatorMember)
844
845 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700846 def is_length_value(self):
847 return isinstance(self.member, OFLengthMember)
848
849 @property
850 def is_public(self):
851 return not (self.is_pad or self.is_length_value)
852
853 @property
854 def is_data(self):
855 return isinstance(self.member, OFDataMember) and self.name != "version"
856
857 @property
858 def is_fixed_value(self):
859 return hasattr(self.member, "value") or self.name == "version" \
860 or ( self.name == "length" and self.msg.is_fixed_length) \
861 or ( self.name == "len" and self.msg.is_fixed_length)
862
863 @property
864 def value(self):
865 if self.name == "version":
866 return self.msg.version.int_version
867 elif self.name == "length" or self.name == "len":
868 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700869 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700870 return self.java_type.format_value(self.member.value)
871
872 @property
873 def priv_value(self):
874 if self.name == "version":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700875 return self.java_type.format_value(self.msg.version.int_version, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700876 elif self.name == "length" or self.name == "len":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700877 return self.java_type.format_value(self.msg.length, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700878 else:
879 return self.java_type.format_value(self.member.value, pub_type=False)
880
Andreas Wundsam27303462013-07-16 12:52:35 -0700881
882 @property
883 def is_writeable(self):
884 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
885
886 def get_type_value_info(self, version):
887 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700888
889 @property
890 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700891 if hasattr(self.member, "length"):
892 return self.member.length
893 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700894 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700895 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700896
897 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700898 def for_of_member(java_class, member):
899 if isinstance(member, OFPadMember):
900 return JavaMember(None, "", None, member)
901 else:
902 if member.name == 'len':
903 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700904 elif member.name == 'value_mask':
905 name = 'mask'
Andreas Wundsamacd57d52013-10-18 17:35:01 -0700906 elif member.name == 'group_id':
907 name = 'group'
Andreas Wundsam27303462013-07-16 12:52:35 -0700908 else:
909 name = java_type.name_c_to_camel(member.name)
910 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
911 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700912
913 @property
914 def is_universal(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800915 for version, ir_class in self.msg.ir_class.version_classes.items():
916 if not ir_class.member_by_name(self.member.name):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700917 return False
918 return True
919
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700920 @property
921 def is_virtual(self):
922 return False
923
Andreas Wundsam27303462013-07-16 12:52:35 -0700924 def __hash__(self):
925 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700926
Andreas Wundsam27303462013-07-16 12:52:35 -0700927 def __eq__(self, other):
928 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700929 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700930 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700931
Andreas Wundsamf1949682013-09-23 14:48:31 -0700932 @property
933 def is_nullable(self):
934 return self.name in model.nullable_map[self.msg.name]
935
936
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700937class JavaVirtualMember(JavaMember):
938 """ 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 -0800939 def __init__(self, msg, name, java_type, value=None, custom_template=None):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700940 JavaMember.__init__(self, msg, name, java_type, member=None)
941 self._value = value
Andreas Wundsam4b8661f2013-11-05 17:17:28 -0800942 self.custom_template = custom_template
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700943
944 @property
945 def is_fixed_value(self):
946 return True
947
948 @property
949 def value(self):
950 return self._value
951
952 @property
953 def priv_value(self):
954 return self._value
955
956
957 @property
958 def is_universal(self):
959 return True
960
961 @property
962 def is_virtual(self):
963 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700964
965#######################################################################
966### Unit Test
967#######################################################################
968
Yotam Harchol466b3212013-08-15 12:14:46 -0700969class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700970 def __init__(self, java_class):
971 self.java_class = java_class
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800972 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.dotless_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700973 name=java_class.c_name[3:])
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800974 glob_file_name = "of{version}/{name}__*.data".format(version=java_class.version.dotless_version,
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -0700975 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700976 test_class_name = self.java_class.name + "Test"
977 self.test_units = []
978 if test_data.exists(first_data_file_name):
979 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -0700980
Yotam Harchol466b3212013-08-15 12:14:46 -0700981 i = 1
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -0700982 for f in test_data.glob(glob_file_name):
983 m = re.match(".*__(.*).data", f)
984 if m:
985 suffix = java_type.name_c_to_caps_camel(m.group(1))
986 else:
987 suffix = str(i)
988 i += 1
989 test_class_name = self.java_class.name + suffix + "Test"
990 self.test_units.append(JavaUnitTest(java_class, f, test_class_name))
Andreas Wundsamf1949682013-09-23 14:48:31 -0700991
Yotam Harchol466b3212013-08-15 12:14:46 -0700992 @property
993 def package(self):
994 return self.java_class.package
995
996 @property
997 def has_test_data(self):
998 return len(self.test_units) > 0
999
1000 @property
1001 def length(self):
1002 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -07001003
Yotam Harchol466b3212013-08-15 12:14:46 -07001004 def get_test_unit(self, i):
1005 return self.test_units[i]
1006
1007
1008class JavaUnitTest(object):
1009 def __init__(self, java_class, file_name=None, test_class_name=None):
1010 self.java_class = java_class
1011 if file_name is None:
Andreas Wundsamc8912c12013-11-15 13:44:48 -08001012 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.dotless_version,
Yotam Harchol466b3212013-08-15 12:14:46 -07001013 name=java_class.c_name[3:])
1014 else:
1015 self.data_file_name = file_name
1016 if test_class_name is None:
1017 self.test_class_name = self.java_class.name + "Test"
1018 else:
1019 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001020
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001021 @property
1022 def package(self):
1023 return self.java_class.package
1024
1025 @property
1026 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001027 return self.test_class_name
Yotam Harchol595c6442013-09-27 16:29:08 -07001028
1029 @property
1030 def interface(self):
1031 return self.java_class.interface
1032
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001033 @property
1034 def has_test_data(self):
1035 return test_data.exists(self.data_file_name)
1036
1037 @property
1038 @memoize
1039 def test_data(self):
1040 return test_data.read(self.data_file_name)
1041
1042
Andreas Wundsam27303462013-07-16 12:52:35 -07001043#######################################################################
1044### Enums
1045#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001046
Andreas Wundsam27303462013-07-16 12:52:35 -07001047class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001048 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001049 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001050
Rob Vaterlausfeee3712013-09-30 11:24:19 -07001051 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001052
Andreas Wundsam27303462013-07-16 12:52:35 -07001053 # Port_features has constants that start with digits
1054 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001055
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001056 self.version_enums = version_enum_map
1057
1058 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1059 for version, ir_enum in version_enum_map.items():
1060 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001061 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1062
Andreas Wundsam27303462013-07-16 12:52:35 -07001063 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001064 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001065
1066 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 -07001067 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001068
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001069 self.metadata = model.enum_metadata_map[self.name]
1070
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001071 def wire_type(self, version):
1072 ir_enum = self.version_enums[version]
1073 if "wire_type" in ir_enum.params:
1074 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1075 else:
1076 return java_type.u8
1077
1078 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001079 @memoize
1080 def is_bitmask(self):
1081 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1082
1083 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001084 def versions(self):
1085 return self.version_enums.keys()
1086
Andreas Wundsam27303462013-07-16 12:52:35 -07001087 @memoize
1088 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001089 res = find(lambda e: e.name == name, self.entries)
1090 if res:
1091 return res
1092 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001093 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1094
1095 @memoize
1096 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001097 res = find(lambda e: e.c_name == name, self.entries)
1098 if res:
1099 return res
1100 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001101 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1102
1103 @memoize
1104 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001105 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1106 if res:
1107 return res
1108 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001109 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1110
1111# values: Map JavaVersion->Value
1112class JavaEnumEntry(object):
1113 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001114 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001115 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1116 self.values = values
1117
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001118 @property
1119 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001120 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001121
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001122 def has_value(self, version):
1123 return version in self.values
1124
Andreas Wundsam27303462013-07-16 12:52:35 -07001125 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001126 return self.values[version]
1127
1128 def format_value(self, version):
1129 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001130 return res
1131
Andreas Wundsam27303462013-07-16 12:52:35 -07001132 def all_values(self, versions, not_present=None):
1133 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001134
1135 @property
1136 @memoize
1137 def masked_enum_group(self):
1138 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1139 return group
1140
1141 @property
1142 @memoize
1143 def is_mask(self):
1144 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])