blob: 7aa48578bcd74cafc2d7c58e3e4ec87f1bf8ea50 [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 Laneea356862013-12-09 18:02:36 -0800473 elif self.ir_class.is_instanceof("of_action_id"):
474 if self.ir_class.is_subclassof('of_action_id_bsn'):
475 return ("actionid", "OFActionIdBsn", None)
476 elif self.ir_class.is_subclassof('of_action_id_nicira'):
477 return ("actionid", "OFActionIdNicira", None)
478 elif self.ir_class.is_subclassof('of_action_id_experimenter'):
479 return ("actionid", "OFActionIdExperimenter", None)
480 else:
481 return ("actionid", "OFActionId", None)
Rich Lanef33f32f2013-11-18 15:49:54 -0800482 elif self.ir_class.is_instruction:
483 if self.ir_class.is_subclassof('of_instruction_bsn'):
484 return ("instruction", "OFInstructionBsn", None)
485 elif self.ir_class.is_subclassof('of_instruction_experimenter'):
486 return ("instruction", "OFInstructionExperimenter", None)
487 else:
488 return ("instruction", "OFInstruction", None)
Rich Laneea356862013-12-09 18:02:36 -0800489 elif self.ir_class.is_instanceof('of_instruction_id'):
490 if self.ir_class.is_subclassof('of_instruction_id_bsn'):
491 return ("instructionid", "OFInstructionIdBsn", None)
492 elif self.ir_class.is_subclassof('of_instruction_id_experimenter'):
493 return ("instructionid", "OFInstructionIdExperimenter", None)
494 else:
495 return ("instructionid", "OFInstructionId", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700496 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700497 return ("", "OFBsnVport", None)
498 elif self.name == "OFOxm":
499 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700500 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800501 if self.member_by_name("value") is not None:
502 return ("oxm", "OFOxm<%s>" % self.member_by_name("value").java_type.public_type, None)
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700503 else:
504 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700505 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700506 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700507 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700508 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700509 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700510 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700511 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700512 return ("", "OFHelloElem", None)
Rich Lane26847562013-10-08 13:44:47 -0700513 elif loxi_utils.class_is_table_feature_prop(self.c_name):
514 return ("", "OFTableFeatureProp", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700515 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700516 return ("", None, None)
517
518 @property
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800519
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700520 @memoize
521 def writeable_members(self):
522 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700523
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700524 @memoize
525 def member_by_name(self, name):
526 return find(lambda m: m.name == name, self.members)
527
Andreas Wundsam27303462013-07-16 12:52:35 -0700528 @property
529 @memoize
530 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700531 return self.ir_model_members + self.virtual_members
532
533 @property
534 @memoize
535 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700536 """return a list of all members to be exposed by this interface. Corresponds to
537 the union of the members of the vesioned classes without length, fieldlength
538 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700539 all_versions = []
540 member_map = collections.OrderedDict()
541
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800542 member_version_map = {}
Andreas Wundsam27303462013-07-16 12:52:35 -0700543 for (version, of_class) in self.version_map.items():
544 for of_member in of_class.members:
545 if isinstance(of_member, OFLengthMember) or \
546 isinstance(of_member, OFFieldLengthMember) or \
547 isinstance(of_member, OFPadMember):
548 continue
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800549 java_member = JavaMember.for_of_member(self, of_member)
Andreas Wundsam27303462013-07-16 12:52:35 -0700550 if of_member.name not in member_map:
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800551 member_map[of_member.name] = java_member
552 member_version_map[of_member.name] = version
553 else:
554 existing = member_map[of_member.name]
555
556 if existing.java_type.public_type != java_member.java_type.public_type:
557 raise Exception(
558 "Error constructing interface {}: type signatures do not match up between versions.\n"
559 " Member Name: {}\n"
560 " Existing: Version={}, Java={}, IR={}\n"
561 " New: Version={}, Java={}, IR={}"
562 .format(self.name, existing.name,
563 member_version_map[of_member.name], existing.java_type.public_type, existing.member.oftype,
564 version, java_member.java_type.public_type, java_member.member.oftype)
565 )
Andreas Wundsam27303462013-07-16 12:52:35 -0700566
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700567 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 -0700568
569 @property
570 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700571 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700572 if self.name == "OFOxm":
Andreas Wundsama0981022013-10-02 18:15:06 -0700573 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700574 JavaVirtualMember(self, "value", java_type.generic_t),
575 JavaVirtualMember(self, "mask", java_type.generic_t),
576 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
577 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800578 JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype("T"))
Andreas Wundsama0981022013-10-02 18:15:06 -0700579 ]
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800580 elif self.ir_class.is_subclassof("of_oxm"):
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800581 value = find(lambda m: m.name=="value", self.ir_model_members)
582 if value:
583 field_type = java_type.make_match_field_jtype(value.java_type.public_type)
584 else:
585 field_type = java_type.make_match_field_jtype()
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700586
Andreas Wundsama0981022013-10-02 18:15:06 -0700587 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700588 JavaVirtualMember(self, "matchField", field_type),
589 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800590 JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype(value.java_type.public_type),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800591 custom_template=lambda builder: "OFOxm{}_getCanonical.java".format(".Builder" if builder else "")),
Andreas Wundsama0981022013-10-02 18:15:06 -0700592 ]
593 if not find(lambda x: x.name == "mask", self.ir_model_members):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800594 virtual_members.append(
595 JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type))
Andreas Wundsama0981022013-10-02 18:15:06 -0700596
597 if not find(lambda m: m.name == "version", self.ir_model_members):
598 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version))
599
600 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700601
602 @property
603 @memoize
604 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700605 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700606 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 -0700607
608 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700609 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700610 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700611 return len(self.all_versions) == len(model.versions)
612
613 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700614 @memoize
615 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700616 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700617 return self.version_map.keys()
618
Andreas Wundsam5204de22013-07-30 11:34:45 -0700619 def has_version(self, version):
620 return version in self.version_map
621
Andreas Wundsam27303462013-07-16 12:52:35 -0700622 def versioned_class(self, version):
623 return JavaOFClass(self, version, self.version_map[version])
624
625 @property
626 @memoize
627 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700628 return [ self.versioned_class(version) for version in self.all_versions ]
629
630#######################################################################
631### (Versioned) Classes
632#######################################################################
633
634class JavaOFClass(object):
635 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700636 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700637 """
638 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700639 """
640 @param interface JavaOFInterface instance of the parent interface
641 @param version JavaOFVersion
642 @param ir_class OFClass from loxi_ir
643 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700644 self.interface = interface
645 self.ir_class = ir_class
646 self.c_name = self.ir_class.name
647 self.version = version
648 self.constant_name = self.c_name.upper().replace("OF_", "")
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800649 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.dotless_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700650 self.generated = False
651
652 @property
653 @memoize
654 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700655 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700656
657 @property
658 def name(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800659 return "%sVer%s" % (self.interface.name, self.version.dotless_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700660
661 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700662 def variable_name(self):
Andreas Wundsam781d99f2013-10-23 15:25:56 -0700663 return self.name[2].lower() + self.name[3:]
Andreas Wundsam5204de22013-07-30 11:34:45 -0700664
665 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700666 def length(self):
667 if self.is_fixed_length:
668 return self.min_length
669 else:
670 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
671
672 @property
673 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700674 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800675 return self.ir_class.base_length
Andreas Wundsam27303462013-07-16 12:52:35 -0700676
677 @property
678 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700679 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800680 return self.ir_class.is_fixed_length and not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700681
682 def all_properties(self):
683 return self.interface.members
684
Andreas Wundsam27303462013-07-16 12:52:35 -0700685 @property
686 @memoize
687 def data_members(self):
688 return [ prop for prop in self.members if prop.is_data ]
689
690 @property
691 @memoize
692 def fixed_value_members(self):
693 return [ prop for prop in self.members if prop.is_fixed_value ]
694
695 @property
696 @memoize
697 def public_members(self):
698 return [ prop for prop in self.members if prop.is_public ]
699
700 @property
701 @memoize
702 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700703 return self.ir_model_members + self.virtual_members
704
705 @property
Andreas Wundsama0981022013-10-02 18:15:06 -0700706 @memoize
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700707 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700708 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700709 return tuple(members)
710
711 @property
712 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700713 virtual_members = []
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800714 if self.ir_class.is_subclassof("of_oxm"):
715 value_member = find(lambda m: m.name, self.ir_model_members)
716 if value_member:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700717 oxm_entry = model.oxm_map[self.interface.name]
Andreas Wundsama0981022013-10-02 18:15:06 -0700718 virtual_members += [
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800719 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 -0700720 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800721 ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700722 else:
Andreas Wundsama0981022013-10-02 18:15:06 -0700723 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700724 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
725 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800726 ]
Andreas Wundsama0981022013-10-02 18:15:06 -0700727 if not find(lambda m: m.name == "version", self.ir_model_members):
728 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version, "OFVersion.%s" % self.version.constant_version))
729
730 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700731
Andreas Wundsam661a2222013-11-05 17:18:59 -0800732 @memoize
733 def member_by_name(self, name):
734 return find(lambda m: m.name == name, self.members)
735
Andreas Wundsam27303462013-07-16 12:52:35 -0700736 def all_versions(self):
737 return [ JavaOFVersion(int_version)
738 for int_version in of_g.unified[self.c_name]
739 if int_version != 'union' and int_version != 'object_id' ]
740
741 def version_is_inherited(self, version):
742 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
743
744 def inherited_from(self, version):
745 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
746
747 @property
748 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700749 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
750
751 @property
752 def discriminator(self):
753 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700754
755 @property
756 def is_extension(self):
757 return type_maps.message_is_extension(self.c_name, -1)
758
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700759 @property
760 def align(self):
761 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
762
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700763 @property
Andreas Wundsam5da68512013-10-22 22:18:00 -0700764 def length_includes_align(self):
765 return self.ir_class.params['length_includes_align'] == "True" if 'length_includes_align' in self.ir_class.params else False
766
767 @property
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700768 @memoize
769 def superclass(self):
770 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
771
772 @property
773 @memoize
774 def subclasses(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800775 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass
776 and c.ir_class.superclass.name == self.c_name ]
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700777
Andreas Wundsam27303462013-07-16 12:52:35 -0700778#######################################################################
779### Member
780#######################################################################
781
782
783class JavaMember(object):
784 """ Models a property (member) of an openflow class. """
785 def __init__(self, msg, name, java_type, member):
786 self.msg = msg
787 self.name = name
788 self.java_type = java_type
789 self.member = member
790 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700791
792 @property
793 def title_name(self):
794 return self.name[0].upper() + self.name[1:]
795
796 @property
797 def constant_name(self):
798 return self.c_name.upper()
799
800 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700801 def getter_name(self):
802 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
803
804 @property
805 def setter_name(self):
806 return "set" + self.title_name
807
808 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700809 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700810 if self.is_fixed_value:
811 return self.constant_name
812 else:
813 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700814
815 @property
816 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700817 if self.is_fixed_value:
818 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700819 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700820 default = self.java_type.default_op(self.msg.version)
821 if default == "null" and not self.is_nullable:
822 return None
823 else:
824 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700825
826 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700827 def enum_value(self):
828 if self.name == "version":
829 return "OFVersion.%s" % self.msg.version.constant_version
830
831 java_type = self.java_type.public_type;
832 try:
833 global model
834 enum = model.enum_by_name(java_type)
835 entry = enum.entry_by_version_value(self.msg.version, self.value)
836 return "%s.%s" % ( enum.name, entry.name)
837 except KeyError, e:
Andreas Wundsamaa8a9182013-11-19 09:45:01 -0800838 logger.debug("No enum found", e)
Andreas Wundsam27303462013-07-16 12:52:35 -0700839 return self.value
840
841 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700842 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700843 return isinstance(self.member, OFPadMember)
844
845 def is_type_value(self, version=None):
846 if(version==None):
847 return any(self.is_type_value(version) for version in self.msg.all_versions)
848 try:
849 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
850 except:
851 return False
852
853 @property
854 def is_field_length_value(self):
855 return isinstance(self.member, OFFieldLengthMember)
856
857 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700858 def is_discriminator(self):
859 return isinstance(self.member, OFDiscriminatorMember)
860
861 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700862 def is_length_value(self):
863 return isinstance(self.member, OFLengthMember)
864
865 @property
866 def is_public(self):
867 return not (self.is_pad or self.is_length_value)
868
869 @property
870 def is_data(self):
871 return isinstance(self.member, OFDataMember) and self.name != "version"
872
873 @property
874 def is_fixed_value(self):
875 return hasattr(self.member, "value") or self.name == "version" \
876 or ( self.name == "length" and self.msg.is_fixed_length) \
877 or ( self.name == "len" and self.msg.is_fixed_length)
878
879 @property
880 def value(self):
881 if self.name == "version":
882 return self.msg.version.int_version
883 elif self.name == "length" or self.name == "len":
884 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700885 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700886 return self.java_type.format_value(self.member.value)
887
888 @property
889 def priv_value(self):
890 if self.name == "version":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700891 return self.java_type.format_value(self.msg.version.int_version, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700892 elif self.name == "length" or self.name == "len":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700893 return self.java_type.format_value(self.msg.length, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700894 else:
895 return self.java_type.format_value(self.member.value, pub_type=False)
896
Andreas Wundsam27303462013-07-16 12:52:35 -0700897
898 @property
899 def is_writeable(self):
900 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
901
902 def get_type_value_info(self, version):
903 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700904
905 @property
906 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700907 if hasattr(self.member, "length"):
908 return self.member.length
909 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700910 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700911 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700912
913 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700914 def for_of_member(java_class, member):
915 if isinstance(member, OFPadMember):
916 return JavaMember(None, "", None, member)
917 else:
918 if member.name == 'len':
919 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700920 elif member.name == 'value_mask':
921 name = 'mask'
Andreas Wundsamacd57d52013-10-18 17:35:01 -0700922 elif member.name == 'group_id':
923 name = 'group'
Andreas Wundsam27303462013-07-16 12:52:35 -0700924 else:
925 name = java_type.name_c_to_camel(member.name)
926 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
927 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700928
929 @property
930 def is_universal(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800931 for version, ir_class in self.msg.ir_class.version_classes.items():
932 if not ir_class.member_by_name(self.member.name):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700933 return False
934 return True
935
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700936 @property
937 def is_virtual(self):
938 return False
939
Andreas Wundsam27303462013-07-16 12:52:35 -0700940 def __hash__(self):
941 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700942
Andreas Wundsam27303462013-07-16 12:52:35 -0700943 def __eq__(self, other):
944 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700945 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700946 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700947
Andreas Wundsamf1949682013-09-23 14:48:31 -0700948 @property
949 def is_nullable(self):
950 return self.name in model.nullable_map[self.msg.name]
951
952
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700953class JavaVirtualMember(JavaMember):
954 """ 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 -0800955 def __init__(self, msg, name, java_type, value=None, custom_template=None):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700956 JavaMember.__init__(self, msg, name, java_type, member=None)
957 self._value = value
Andreas Wundsam4b8661f2013-11-05 17:17:28 -0800958 self.custom_template = custom_template
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700959
960 @property
961 def is_fixed_value(self):
962 return True
963
964 @property
965 def value(self):
966 return self._value
967
968 @property
969 def priv_value(self):
970 return self._value
971
972
973 @property
974 def is_universal(self):
975 return True
976
977 @property
978 def is_virtual(self):
979 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700980
981#######################################################################
982### Unit Test
983#######################################################################
984
Yotam Harchol466b3212013-08-15 12:14:46 -0700985class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700986 def __init__(self, java_class):
987 self.java_class = java_class
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800988 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.dotless_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700989 name=java_class.c_name[3:])
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800990 glob_file_name = "of{version}/{name}__*.data".format(version=java_class.version.dotless_version,
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -0700991 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700992 test_class_name = self.java_class.name + "Test"
993 self.test_units = []
994 if test_data.exists(first_data_file_name):
995 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -0700996
Yotam Harchol466b3212013-08-15 12:14:46 -0700997 i = 1
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -0700998 for f in test_data.glob(glob_file_name):
999 m = re.match(".*__(.*).data", f)
1000 if m:
1001 suffix = java_type.name_c_to_caps_camel(m.group(1))
1002 else:
1003 suffix = str(i)
1004 i += 1
1005 test_class_name = self.java_class.name + suffix + "Test"
1006 self.test_units.append(JavaUnitTest(java_class, f, test_class_name))
Andreas Wundsamf1949682013-09-23 14:48:31 -07001007
Yotam Harchol466b3212013-08-15 12:14:46 -07001008 @property
1009 def package(self):
1010 return self.java_class.package
1011
1012 @property
1013 def has_test_data(self):
1014 return len(self.test_units) > 0
1015
1016 @property
1017 def length(self):
1018 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -07001019
Yotam Harchol466b3212013-08-15 12:14:46 -07001020 def get_test_unit(self, i):
1021 return self.test_units[i]
1022
1023
1024class JavaUnitTest(object):
1025 def __init__(self, java_class, file_name=None, test_class_name=None):
1026 self.java_class = java_class
1027 if file_name is None:
Andreas Wundsamc8912c12013-11-15 13:44:48 -08001028 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.dotless_version,
Yotam Harchol466b3212013-08-15 12:14:46 -07001029 name=java_class.c_name[3:])
1030 else:
1031 self.data_file_name = file_name
1032 if test_class_name is None:
1033 self.test_class_name = self.java_class.name + "Test"
1034 else:
1035 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001036
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001037 @property
1038 def package(self):
1039 return self.java_class.package
1040
1041 @property
1042 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001043 return self.test_class_name
Yotam Harchol595c6442013-09-27 16:29:08 -07001044
1045 @property
1046 def interface(self):
1047 return self.java_class.interface
1048
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001049 @property
1050 def has_test_data(self):
1051 return test_data.exists(self.data_file_name)
1052
1053 @property
1054 @memoize
1055 def test_data(self):
1056 return test_data.read(self.data_file_name)
1057
1058
Andreas Wundsam27303462013-07-16 12:52:35 -07001059#######################################################################
1060### Enums
1061#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001062
Andreas Wundsam27303462013-07-16 12:52:35 -07001063class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001064 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001065 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001066
Rob Vaterlausfeee3712013-09-30 11:24:19 -07001067 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001068
Andreas Wundsam27303462013-07-16 12:52:35 -07001069 # Port_features has constants that start with digits
1070 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001071
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001072 self.version_enums = version_enum_map
1073
1074 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1075 for version, ir_enum in version_enum_map.items():
1076 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001077 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1078
Andreas Wundsam27303462013-07-16 12:52:35 -07001079 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001080 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001081
1082 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 -07001083 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001084
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001085 self.metadata = model.enum_metadata_map[self.name]
1086
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001087 def wire_type(self, version):
1088 ir_enum = self.version_enums[version]
1089 if "wire_type" in ir_enum.params:
1090 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1091 else:
1092 return java_type.u8
1093
1094 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001095 @memoize
1096 def is_bitmask(self):
1097 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1098
1099 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001100 def versions(self):
1101 return self.version_enums.keys()
1102
Andreas Wundsam27303462013-07-16 12:52:35 -07001103 @memoize
1104 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001105 res = find(lambda e: e.name == name, 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 name %s" % (self.name, name))
1110
1111 @memoize
1112 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001113 res = find(lambda e: e.c_name == name, self.entries)
1114 if res:
1115 return res
1116 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001117 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1118
1119 @memoize
1120 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001121 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1122 if res:
1123 return res
1124 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001125 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1126
1127# values: Map JavaVersion->Value
1128class JavaEnumEntry(object):
1129 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001130 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001131 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1132 self.values = values
1133
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001134 @property
1135 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001136 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001137
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001138 def has_value(self, version):
1139 return version in self.values
1140
Andreas Wundsam27303462013-07-16 12:52:35 -07001141 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001142 return self.values[version]
1143
1144 def format_value(self, version):
1145 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001146 return res
1147
Andreas Wundsam27303462013-07-16 12:52:35 -07001148 def all_values(self, versions, not_present=None):
1149 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001150
1151 @property
1152 @memoize
1153 def masked_enum_group(self):
1154 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1155 return group
1156
1157 @property
1158 @memoize
1159 def is_mask(self):
1160 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])