blob: 6f867069d7e92e701ca1a44b398c7b466f5e0f6a [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)
Rich Lane13730732013-12-03 13:05:19 -080071 write_blacklist = defaultdict(
72 lambda: set(),
73 OFOxm=set(('typeLen',)),
74 OFAction=set(('type',)),
75 OFInstruction=set(('type',)),
76 OFFlowMod=set(('command', )),
77 OFExperimenter=set(('data','subtype')),
78 OFActionExperimenter=set(('data',)),
79 OFBsnTlv=set(('type',)))
Andreas Wundsamf1949682013-09-23 14:48:31 -070080 # interfaces that are virtual
Andreas Wundsam001b1822013-08-02 22:25:55 -070081 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070082
Andreas Wundsamf1949682013-09-23 14:48:31 -070083 # Registry of nullable properties:
84 # ${java_class_name} -> set(${java_property_name})
85 nullable_map = defaultdict(lambda: set(),
86 )
87
88 # represents a subgroup of a bitmask enum that is actualy a normal enumerable within a masked part of the enum
89 # e.g., the flags STP.* in OF1.0 port state are bit mask entries, but instead enumerables according to the mask "STP_MASK"
90 # name: a name for the group
91 # mask: java name of the enum entry that defines the mask
92 # members: set of names of the members of the group
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -070093 MaskedEnumGroup = namedtuple("MaskedEnumGroup", ("name", "mask", "members"))
94
Andreas Wundsamf1949682013-09-23 14:48:31 -070095 # registry of MaskedEnumGroups (see above).
96 # map: ${java_enum_name}: tuple(MaskedEnumGroup)
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -070097 masked_enum_groups = defaultdict(lambda: (),
Andreas Wundsamaebe5182013-09-24 13:01:07 -070098 OFPortState = (MaskedEnumGroup("stp_flags", mask="STP_MASK", members=set(("STP_LISTEN", "STP_LEARN", "STP_FORWARD", "STP_BLOCK"))), ),
99 OFConfigFlags = (
100 MaskedEnumGroup("frag_flags", mask="FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
Andreas Wundsam376cef52013-09-24 13:52:18 -0700101 ),
102 OFTableConfig = (
103 MaskedEnumGroup("table_miss_flags", mask="TABLE_MISS_MASK", members=set(("TABLE_MISS_CONTROLLER", "TABLE_MISS_CONTINUE", "TABLE_MISS_DROP"))),
104 ),
Andreas Wundsam057540b2013-11-19 16:51:36 -0800105 OFGetConfigReply = (
106 MaskedEnumGroup("flags", mask="OFP_FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
107 ),
108 OFSetConfig = (
109 MaskedEnumGroup("flags", mask="OFP_FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
110 ),
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700111 )
112
Andreas Wundsamf1949682013-09-23 14:48:31 -0700113 # represents a metadata property associated with an EnumClass
114 # name:
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700115 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700116 """
117 represents a metadata property associated with an Enum Class
118 @param name name of metadata property
119 @param type java_type instance describing the type
120 @value: Generator function f(entry) that generates the value
121 """
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700122 @property
123 def variable_name(self):
124 return self.name[0].lower() + self.name[1:]
125
126 @property
127 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700128 prefix = "is" if self.type == java_type.boolean else "get"
129 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700130
Andreas Wundsamf1949682013-09-23 14:48:31 -0700131 """ Metadata container. """
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700132 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
133
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700134 def gen_port_speed(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700135 """ Generator function for OFortFeatures.PortSpeed"""
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700136 splits = enum_entry.name.split("_")
137 if len(splits)>=2:
138 m = re.match(r'\d+[MGTP]B', splits[1])
139 if m:
140 return "PortSpeed.SPEED_{}".format(splits[1])
141 return "PortSpeed.SPEED_NONE";
142
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700143 def gen_stp_state(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700144 """ Generator function for OFPortState.StpState"""
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700145 splits = enum_entry.name.split("_")
146 if len(splits)>=1:
147 if splits[0] == "STP":
148 return "true"
149 return "false"
150
Andreas Wundsamf1949682013-09-23 14:48:31 -0700151 # registry for metadata properties for enums
152 # map: ${java_enum_name}: OFEnumMetadata
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700153 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
Rob Vaterlausa049dee2013-09-18 16:18:37 -0700154 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
155 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700156 )
157
Andreas Wundsam27303462013-07-16 12:52:35 -0700158 @property
159 @memoize
160 def versions(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800161 return OrderedSet( JavaOFVersion(ir_version) for ir_version in OFVersions.target_versions)
Andreas Wundsam27303462013-07-16 12:52:35 -0700162
163 @property
164 @memoize
165 def interfaces(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800166 interfaces = [ JavaOFInterface(ir_class) for ir_class in loxi_globals.unified.classes ]
Andreas Wundsambe168f72013-08-03 22:49:35 -0700167 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
168
Andreas Wundsam27303462013-07-16 12:52:35 -0700169 return interfaces
170
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700171 @memoize
172 def interface_by_name(self, name):
173 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
174
Andreas Wundsam27303462013-07-16 12:52:35 -0700175 @property
176 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700177 def all_classes(self):
178 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
179
180 @property
181 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700182 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700183 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700184
185 for version in self.versions:
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800186 logger.info("version: {}".format(version.ir_version))
187 of_protocol = loxi_globals.ir[version.ir_version]
Andreas Wundsam27303462013-07-16 12:52:35 -0700188 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700189 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700190
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700191 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
192 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700193
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700194 # inelegant - need java name here
195 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700196 return enums
197
198 @memoize
199 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700200 res = find(lambda e: e.name == name, self.enums)
201 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700202 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700203 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700204
Andreas Wundsam5204de22013-07-30 11:34:45 -0700205 @property
206 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700207 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700208 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700209
210 factories = OrderedDict()
211
Andreas Wundsamd4b22692014-01-14 14:17:26 -0800212 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp", "OFErrorMsg", "OFActionId", "OFInstructionId", "OFBsnTlv")
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700213 for base_class in sub_factory_classes:
214 package = base_class[2:].lower()
215 remove_prefix = base_class[2].lower() + base_class[3:]
216
217 # HACK need to have a better way to deal with parameterized base classes
218 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
219
220 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
Andreas Wundsamd1ca4f92013-12-10 18:58:44 -0800221 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={}, xid_generator= (base_class == "OFErrorMsg"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700222
223 factories[""] = OFFactory(
224 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700225 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700226 remove_prefix="",
227 members=[], base_class="OFMessage", sub_factories=OrderedDict(
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700228 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ),
229 xid_generator=True)
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700230
231 for i in self.interfaces:
232 for n, factory in factories.items():
233 if n == "":
234 factory.members.append(i)
235 break
236 else:
237 super_class = self.interface_by_name(n)
238 if i.is_instance_of(super_class):
239 factory.members.append(i)
240 break
241 return factories.values()
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800242
Yotam Harchol595c6442013-09-27 16:29:08 -0700243 @memoize
244 def factory_of(self, interface):
245 for factory in self.of_factories:
246 if interface in factory.members:
247 return factory
248 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700249
250 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700251 """ return wether or not to generate implementation class clazz.
252 Now true for everything except OFTableModVer10.
253 @param clazz JavaOFClass instance
254 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700255 if clazz.interface.name.startswith("OFMatchV"):
256 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700257 elif clazz.name == "OFTableModVer10":
258 # tablemod ver 10 is a hack and has no oftype defined
259 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700260 if loxi_utils.class_is_message(clazz.interface.c_name):
261 return True
262 if loxi_utils.class_is_oxm(clazz.interface.c_name):
263 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700264 if loxi_utils.class_is_action(clazz.interface.c_name):
265 return True
266 if loxi_utils.class_is_instruction(clazz.interface.c_name):
267 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700268 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700269 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700270
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800271 @property
272 @memoize
273 def oxm_map(self):
274 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
275 return OrderedDict( (oxm.name, OxmMapEntry(type_name=oxm.member_by_name("value").java_type.public_type,
276 value=re.sub(r'^of_oxm_', r'', re.sub(r'_masked$', r'', oxm.ir_class.name)).upper(),
277 masked=oxm.ir_class.name.endswith("_masked")))
278 for oxm in self.interfaces if oxm.ir_class.is_subclassof("of_oxm") )
Andreas Wundsam5204de22013-07-30 11:34:45 -0700279
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700280class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories", "xid_generator"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700281 @property
282 def factory_classes(self):
283 return [ OFFactoryClass(
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800284 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.dotless_version),
285 name="{}Ver{}".format(self.name, version.dotless_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700286 interface=self,
287 version=version
288 ) for version in model.versions ]
289
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700290 def method_name(self, member, builder=True):
291 n = member.variable_name
292 if n.startswith(self.remove_prefix):
293 n = n[len(self.remove_prefix):]
294 n = n[0].lower() + n[1:]
295 if builder:
296 return "build" + n[0].upper() + n[1:]
297 else:
298 return n
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800299
Yotam Harchol595c6442013-09-27 16:29:08 -0700300 def of_version(self, version):
301 for fc in self.factory_classes:
302 if fc.version == version:
303 return fc
304 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700305
306OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700307class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
308 @property
309 def base_class(self):
310 return self.interface.base_class
311
312 @property
313 def versioned_base_class(self):
314 base_class_interface = model.interface_by_name(self.interface.base_class)
315 if base_class_interface and base_class_interface.has_version(self.version):
316 return base_class_interface.versioned_class(self.version)
317 else:
318 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700319
Andreas Wundsam27303462013-07-16 12:52:35 -0700320model = JavaModel()
321
322#######################################################################
323### OFVersion
324#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700325
326class JavaOFVersion(object):
327 """ Models a version of OpenFlow. contains methods to convert the internal
328 Loxi version to a java constant / a string """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800329 def __init__(self, ir_version):
330 assert isinstance(ir_version, OFVersion)
331 self.ir_version = ir_version
332 self.int_version = self.ir_version.wire_version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700333
334 @property
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800335 def dotless_version(self):
336 return self.ir_version.version.replace(".", "")
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700337
338 @property
339 def constant_version(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800340 return "OF_" + self.dotless_version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700341
Andreas Wundsam27303462013-07-16 12:52:35 -0700342 def __repr__(self):
343 return "JavaOFVersion(%d)" % self.int_version
344
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700345 def __str__(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800346 return self.ir_version.version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700347
Andreas Wundsam27303462013-07-16 12:52:35 -0700348 def __hash__(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800349 return hash(self.ir_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700350
351 def __eq__(self, other):
352 if other is None or type(self) != type(other):
353 return False
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800354 return (self.ir_version,) == (other.ir_version,)
Andreas Wundsam27303462013-07-16 12:52:35 -0700355
356#######################################################################
357### Interface
358#######################################################################
359
360class JavaOFInterface(object):
361 """ Models an OpenFlow Message class for the purpose of the java class.
362 Version agnostic, in contrast to the loxi_ir python model.
363 """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800364 def __init__(self, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700365 """"
366 @param c_name: loxi style name (e.g., of_flow_add)
367 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
368 """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800369 self.ir_class = ir_class
370 self.c_name = ir_class.name
371 self.version_map = { JavaOFVersion(v): c for v,c in ir_class.version_classes.items() }
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700372 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800373 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 -0700374 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700375 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700376 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700377 # name for use in constants: FLOW_ADD
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800378 self.constant_name = self.c_name.upper().replace("OF_", "")
Andreas Wundsam27303462013-07-16 12:52:35 -0700379
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700380 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700381 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700382 if self.name != parent_interface:
383 self.parent_interface = parent_interface
384 else:
385 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700386
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700387 @property
388 @memoize
389 def all_parent_interfaces(self):
390 return [ "OFObject" ] + \
391 ([ self.parent_interface ] if self.parent_interface else [] )+ \
392 self.additional_parent_interfaces
393 @property
394 @memoize
395 def additional_parent_interfaces(self):
396 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
397 m = re.match(r'(.*)Request$', self.name)
398 if m:
399 reply_name = m.group(1) + "Reply"
400 if model.interface_by_name(reply_name):
401 return ["OFRequest<%s>" % reply_name ]
402 return []
403
404
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700405 def is_instance_of(self, other_class):
406 if self == other_class:
407 return True
408 parent = self.super_class
409 if parent is None:
410 return False
411 else:
412 return parent.is_instance_of(other_class)
413
414 @property
415 def super_class(self):
416 if not self.parent_interface:
417 return None
418 else:
419 return model.interface_by_name(self.parent_interface)
420
421
422 def inherited_declaration(self, type_spec="?"):
423 if self.type_annotation:
424 return "%s<%s>" % (self.name, type_spec)
425 else:
426 return "%s" % self.name
427
428 @property
429 def type_variable(self):
430 if self.type_annotation:
431 return "<T>"
432 else:
433 return "";
434
Andreas Wundsam27303462013-07-16 12:52:35 -0700435 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700436 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
437 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
438 # model (note, that the loxi model is on versioned classes). Should check/infer the
439 # inheritance information from the versioned lox_ir classes.
Andreas Wundsamd6b0cb02013-09-28 18:55:56 -0700440 if re.match(r'OFStatsRequest$', self.name):
441 return ("", "OFMessage", "T extends OFStatsReply")
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800442 elif self.ir_class.is_subclassof('of_stats_request'):
Andreas Wundsam2c0a2d72013-11-15 15:16:36 -0800443 if self.ir_class.is_subclassof('of_bsn_stats_request'):
444 return ("", "OFBsnStatsRequest", None)
445 elif self.ir_class.is_subclassof('of_experimenter_stats_request'):
446 return ("", "OFExperimenterStatsRequest", None)
447 else:
448 return ("", "OFStatsRequest<{}>".format(re.sub(r'Request$', 'Reply', self.name)), None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800449 elif self.ir_class.is_subclassof('of_stats_reply'):
Andreas Wundsam2c0a2d72013-11-15 15:16:36 -0800450 if self.ir_class.is_subclassof('of_bsn_stats_reply'):
451 return ("", "OFBsnStatsReply", None)
452 elif self.ir_class.is_subclassof('of_experimenter_stats_reply'):
453 return ("", "OFExperimenterStatsReply", None)
454 else:
455 return ("", "OFStatsReply", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800456 elif self.ir_class.is_subclassof('of_error_msg'):
Andreas Wundsamd1ca4f92013-12-10 18:58:44 -0800457 return ("errormsg", "OFErrorMsg", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800458 elif self.ir_class.is_subclassof('of_flow_mod'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700459 return ("", "OFFlowMod", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800460 elif self.ir_class.is_subclassof('of_group_mod'):
461 return ("", "OFGroupMod", None)
462 elif self.ir_class.is_subclassof('of_bsn_header'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700463 return ("", "OFBsnHeader", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800464 elif self.ir_class.is_subclassof('of_nicira_header'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700465 return ("", "OFNiciraHeader", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800466 elif self.ir_class.is_subclassof('of_experimenter'):
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700467 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700468 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700469 return ("", "Match", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800470 elif self.ir_class.is_message:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700471 return ("", "OFMessage", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800472 elif self.ir_class.is_action:
473 if self.ir_class.is_subclassof('of_action_bsn'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700474 return ("action", "OFActionBsn", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800475 elif self.ir_class.is_subclassof('of_action_nicira'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700476 return ("action", "OFActionNicira", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800477 elif self.ir_class.is_subclassof('of_action_experimenter'):
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700478 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700479 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700480 return ("action", "OFAction", None)
Rich Laneea356862013-12-09 18:02:36 -0800481 elif self.ir_class.is_instanceof("of_action_id"):
482 if self.ir_class.is_subclassof('of_action_id_bsn'):
483 return ("actionid", "OFActionIdBsn", None)
484 elif self.ir_class.is_subclassof('of_action_id_nicira'):
485 return ("actionid", "OFActionIdNicira", None)
486 elif self.ir_class.is_subclassof('of_action_id_experimenter'):
487 return ("actionid", "OFActionIdExperimenter", None)
488 else:
489 return ("actionid", "OFActionId", None)
Rich Lanef33f32f2013-11-18 15:49:54 -0800490 elif self.ir_class.is_instruction:
491 if self.ir_class.is_subclassof('of_instruction_bsn'):
492 return ("instruction", "OFInstructionBsn", None)
493 elif self.ir_class.is_subclassof('of_instruction_experimenter'):
494 return ("instruction", "OFInstructionExperimenter", None)
495 else:
496 return ("instruction", "OFInstruction", None)
Rich Laneea356862013-12-09 18:02:36 -0800497 elif self.ir_class.is_instanceof('of_instruction_id'):
498 if self.ir_class.is_subclassof('of_instruction_id_bsn'):
499 return ("instructionid", "OFInstructionIdBsn", None)
500 elif self.ir_class.is_subclassof('of_instruction_id_experimenter'):
501 return ("instructionid", "OFInstructionIdExperimenter", None)
502 else:
503 return ("instructionid", "OFInstructionId", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700504 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700505 return ("", "OFBsnVport", None)
506 elif self.name == "OFOxm":
507 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700508 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800509 if self.member_by_name("value") is not None:
510 return ("oxm", "OFOxm<%s>" % self.member_by_name("value").java_type.public_type, None)
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700511 else:
512 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700513 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700514 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700515 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700516 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700517 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700518 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700519 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700520 return ("", "OFHelloElem", None)
Rich Lane26847562013-10-08 13:44:47 -0700521 elif loxi_utils.class_is_table_feature_prop(self.c_name):
522 return ("", "OFTableFeatureProp", None)
Rich Lane13730732013-12-03 13:05:19 -0800523 elif loxi_utils.class_is_bsn_tlv(self.c_name):
Andreas Wundsamd4b22692014-01-14 14:17:26 -0800524 return ("bsntlv", "OFBsnTlv", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700525 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700526 return ("", None, None)
527
528 @property
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800529
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700530 @memoize
531 def writeable_members(self):
532 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700533
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700534 @memoize
535 def member_by_name(self, name):
536 return find(lambda m: m.name == name, self.members)
537
Andreas Wundsam27303462013-07-16 12:52:35 -0700538 @property
539 @memoize
540 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700541 return self.ir_model_members + self.virtual_members
542
543 @property
544 @memoize
545 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700546 """return a list of all members to be exposed by this interface. Corresponds to
547 the union of the members of the vesioned classes without length, fieldlength
548 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700549 all_versions = []
550 member_map = collections.OrderedDict()
551
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800552 member_version_map = {}
Andreas Wundsam27303462013-07-16 12:52:35 -0700553 for (version, of_class) in self.version_map.items():
554 for of_member in of_class.members:
555 if isinstance(of_member, OFLengthMember) or \
556 isinstance(of_member, OFFieldLengthMember) or \
557 isinstance(of_member, OFPadMember):
558 continue
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800559 java_member = JavaMember.for_of_member(self, of_member)
Andreas Wundsam27303462013-07-16 12:52:35 -0700560 if of_member.name not in member_map:
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800561 member_map[of_member.name] = java_member
562 member_version_map[of_member.name] = version
563 else:
564 existing = member_map[of_member.name]
565
566 if existing.java_type.public_type != java_member.java_type.public_type:
567 raise Exception(
568 "Error constructing interface {}: type signatures do not match up between versions.\n"
569 " Member Name: {}\n"
570 " Existing: Version={}, Java={}, IR={}\n"
571 " New: Version={}, Java={}, IR={}"
572 .format(self.name, existing.name,
573 member_version_map[of_member.name], existing.java_type.public_type, existing.member.oftype,
574 version, java_member.java_type.public_type, java_member.member.oftype)
575 )
Andreas Wundsam27303462013-07-16 12:52:35 -0700576
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700577 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 -0700578
579 @property
580 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700581 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700582 if self.name == "OFOxm":
Andreas Wundsama0981022013-10-02 18:15:06 -0700583 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700584 JavaVirtualMember(self, "value", java_type.generic_t),
585 JavaVirtualMember(self, "mask", java_type.generic_t),
586 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
587 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800588 JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype("T"))
Andreas Wundsama0981022013-10-02 18:15:06 -0700589 ]
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800590 elif self.ir_class.is_subclassof("of_oxm"):
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800591 value = find(lambda m: m.name=="value", self.ir_model_members)
592 if value:
593 field_type = java_type.make_match_field_jtype(value.java_type.public_type)
594 else:
595 field_type = java_type.make_match_field_jtype()
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700596
Andreas Wundsama0981022013-10-02 18:15:06 -0700597 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700598 JavaVirtualMember(self, "matchField", field_type),
599 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800600 JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype(value.java_type.public_type),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800601 custom_template=lambda builder: "OFOxm{}_getCanonical.java".format(".Builder" if builder else "")),
Andreas Wundsama0981022013-10-02 18:15:06 -0700602 ]
603 if not find(lambda x: x.name == "mask", self.ir_model_members):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800604 virtual_members.append(
605 JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type))
Andreas Wundsama0981022013-10-02 18:15:06 -0700606
607 if not find(lambda m: m.name == "version", self.ir_model_members):
608 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version))
609
610 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700611
612 @property
613 @memoize
614 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700615 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700616 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 -0700617
618 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700619 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700620 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700621 return len(self.all_versions) == len(model.versions)
622
623 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700624 @memoize
625 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700626 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700627 return self.version_map.keys()
628
Andreas Wundsam5204de22013-07-30 11:34:45 -0700629 def has_version(self, version):
630 return version in self.version_map
631
Andreas Wundsam27303462013-07-16 12:52:35 -0700632 def versioned_class(self, version):
633 return JavaOFClass(self, version, self.version_map[version])
634
635 @property
636 @memoize
637 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700638 return [ self.versioned_class(version) for version in self.all_versions ]
639
640#######################################################################
641### (Versioned) Classes
642#######################################################################
643
644class JavaOFClass(object):
645 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700646 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700647 """
648 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700649 """
650 @param interface JavaOFInterface instance of the parent interface
651 @param version JavaOFVersion
652 @param ir_class OFClass from loxi_ir
653 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700654 self.interface = interface
655 self.ir_class = ir_class
656 self.c_name = self.ir_class.name
657 self.version = version
658 self.constant_name = self.c_name.upper().replace("OF_", "")
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800659 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.dotless_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700660 self.generated = False
661
662 @property
663 @memoize
664 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700665 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700666
667 @property
668 def name(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800669 return "%sVer%s" % (self.interface.name, self.version.dotless_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700670
671 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700672 def variable_name(self):
Andreas Wundsam781d99f2013-10-23 15:25:56 -0700673 return self.name[2].lower() + self.name[3:]
Andreas Wundsam5204de22013-07-30 11:34:45 -0700674
675 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700676 def length(self):
677 if self.is_fixed_length:
678 return self.min_length
679 else:
680 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
681
682 @property
683 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700684 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800685 return self.ir_class.base_length
Andreas Wundsam27303462013-07-16 12:52:35 -0700686
687 @property
688 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700689 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800690 return self.ir_class.is_fixed_length and not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700691
692 def all_properties(self):
693 return self.interface.members
694
Andreas Wundsam27303462013-07-16 12:52:35 -0700695 @property
696 @memoize
697 def data_members(self):
698 return [ prop for prop in self.members if prop.is_data ]
699
700 @property
701 @memoize
702 def fixed_value_members(self):
703 return [ prop for prop in self.members if prop.is_fixed_value ]
704
705 @property
706 @memoize
707 def public_members(self):
708 return [ prop for prop in self.members if prop.is_public ]
709
710 @property
711 @memoize
712 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700713 return self.ir_model_members + self.virtual_members
714
715 @property
Andreas Wundsama0981022013-10-02 18:15:06 -0700716 @memoize
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700717 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700718 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700719 return tuple(members)
720
721 @property
722 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700723 virtual_members = []
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800724 if self.ir_class.is_subclassof("of_oxm"):
725 value_member = find(lambda m: m.name, self.ir_model_members)
726 if value_member:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700727 oxm_entry = model.oxm_map[self.interface.name]
Andreas Wundsama0981022013-10-02 18:15:06 -0700728 virtual_members += [
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800729 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 -0700730 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800731 ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700732 else:
Andreas Wundsama0981022013-10-02 18:15:06 -0700733 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700734 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
735 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800736 ]
Andreas Wundsama0981022013-10-02 18:15:06 -0700737 if not find(lambda m: m.name == "version", self.ir_model_members):
738 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version, "OFVersion.%s" % self.version.constant_version))
739
740 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700741
Andreas Wundsam661a2222013-11-05 17:18:59 -0800742 @memoize
743 def member_by_name(self, name):
744 return find(lambda m: m.name == name, self.members)
745
Andreas Wundsam27303462013-07-16 12:52:35 -0700746 def all_versions(self):
747 return [ JavaOFVersion(int_version)
748 for int_version in of_g.unified[self.c_name]
749 if int_version != 'union' and int_version != 'object_id' ]
750
751 def version_is_inherited(self, version):
752 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
753
754 def inherited_from(self, version):
755 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
756
757 @property
758 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700759 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
760
761 @property
762 def discriminator(self):
763 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700764
765 @property
766 def is_extension(self):
767 return type_maps.message_is_extension(self.c_name, -1)
768
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700769 @property
770 def align(self):
771 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
772
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700773 @property
Andreas Wundsam5da68512013-10-22 22:18:00 -0700774 def length_includes_align(self):
775 return self.ir_class.params['length_includes_align'] == "True" if 'length_includes_align' in self.ir_class.params else False
776
777 @property
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700778 @memoize
779 def superclass(self):
780 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
781
782 @property
783 @memoize
784 def subclasses(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800785 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass
786 and c.ir_class.superclass.name == self.c_name ]
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700787
Andreas Wundsam27303462013-07-16 12:52:35 -0700788#######################################################################
789### Member
790#######################################################################
791
792
793class JavaMember(object):
794 """ Models a property (member) of an openflow class. """
795 def __init__(self, msg, name, java_type, member):
796 self.msg = msg
797 self.name = name
798 self.java_type = java_type
799 self.member = member
800 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700801
802 @property
803 def title_name(self):
804 return self.name[0].upper() + self.name[1:]
805
806 @property
807 def constant_name(self):
808 return self.c_name.upper()
809
810 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700811 def getter_name(self):
812 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
813
814 @property
815 def setter_name(self):
816 return "set" + self.title_name
817
818 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700819 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700820 if self.is_fixed_value:
821 return self.constant_name
822 else:
823 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700824
825 @property
826 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700827 if self.is_fixed_value:
828 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700829 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700830 default = self.java_type.default_op(self.msg.version)
831 if default == "null" and not self.is_nullable:
832 return None
833 else:
834 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700835
836 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700837 def enum_value(self):
838 if self.name == "version":
839 return "OFVersion.%s" % self.msg.version.constant_version
840
841 java_type = self.java_type.public_type;
842 try:
843 global model
844 enum = model.enum_by_name(java_type)
845 entry = enum.entry_by_version_value(self.msg.version, self.value)
846 return "%s.%s" % ( enum.name, entry.name)
847 except KeyError, e:
Andreas Wundsamaa8a9182013-11-19 09:45:01 -0800848 logger.debug("No enum found", e)
Andreas Wundsam27303462013-07-16 12:52:35 -0700849 return self.value
850
851 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700852 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700853 return isinstance(self.member, OFPadMember)
854
855 def is_type_value(self, version=None):
856 if(version==None):
857 return any(self.is_type_value(version) for version in self.msg.all_versions)
858 try:
859 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
860 except:
861 return False
862
863 @property
864 def is_field_length_value(self):
865 return isinstance(self.member, OFFieldLengthMember)
866
867 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700868 def is_discriminator(self):
869 return isinstance(self.member, OFDiscriminatorMember)
870
871 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700872 def is_length_value(self):
873 return isinstance(self.member, OFLengthMember)
874
875 @property
876 def is_public(self):
877 return not (self.is_pad or self.is_length_value)
878
879 @property
880 def is_data(self):
881 return isinstance(self.member, OFDataMember) and self.name != "version"
882
883 @property
884 def is_fixed_value(self):
885 return hasattr(self.member, "value") or self.name == "version" \
886 or ( self.name == "length" and self.msg.is_fixed_length) \
887 or ( self.name == "len" and self.msg.is_fixed_length)
888
889 @property
890 def value(self):
891 if self.name == "version":
892 return self.msg.version.int_version
893 elif self.name == "length" or self.name == "len":
894 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700895 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700896 return self.java_type.format_value(self.member.value)
897
898 @property
899 def priv_value(self):
900 if self.name == "version":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700901 return self.java_type.format_value(self.msg.version.int_version, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700902 elif self.name == "length" or self.name == "len":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700903 return self.java_type.format_value(self.msg.length, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700904 else:
905 return self.java_type.format_value(self.member.value, pub_type=False)
906
Andreas Wundsam27303462013-07-16 12:52:35 -0700907
908 @property
909 def is_writeable(self):
910 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
911
912 def get_type_value_info(self, version):
913 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700914
915 @property
916 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700917 if hasattr(self.member, "length"):
918 return self.member.length
919 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700920 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700921 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700922
923 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700924 def for_of_member(java_class, member):
925 if isinstance(member, OFPadMember):
926 return JavaMember(None, "", None, member)
927 else:
928 if member.name == 'len':
929 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700930 elif member.name == 'value_mask':
931 name = 'mask'
Andreas Wundsamacd57d52013-10-18 17:35:01 -0700932 elif member.name == 'group_id':
933 name = 'group'
Andreas Wundsam27303462013-07-16 12:52:35 -0700934 else:
935 name = java_type.name_c_to_camel(member.name)
936 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
937 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700938
939 @property
940 def is_universal(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800941 for version, ir_class in self.msg.ir_class.version_classes.items():
942 if not ir_class.member_by_name(self.member.name):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700943 return False
944 return True
945
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700946 @property
947 def is_virtual(self):
948 return False
949
Andreas Wundsam27303462013-07-16 12:52:35 -0700950 def __hash__(self):
951 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700952
Andreas Wundsam27303462013-07-16 12:52:35 -0700953 def __eq__(self, other):
954 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700955 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700956 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700957
Andreas Wundsamf1949682013-09-23 14:48:31 -0700958 @property
959 def is_nullable(self):
960 return self.name in model.nullable_map[self.msg.name]
961
962
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700963class JavaVirtualMember(JavaMember):
964 """ 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 -0800965 def __init__(self, msg, name, java_type, value=None, custom_template=None):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700966 JavaMember.__init__(self, msg, name, java_type, member=None)
967 self._value = value
Andreas Wundsam4b8661f2013-11-05 17:17:28 -0800968 self.custom_template = custom_template
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700969
970 @property
971 def is_fixed_value(self):
972 return True
973
974 @property
975 def value(self):
976 return self._value
977
978 @property
979 def priv_value(self):
980 return self._value
981
982
983 @property
984 def is_universal(self):
985 return True
986
987 @property
988 def is_virtual(self):
989 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700990
991#######################################################################
992### Unit Test
993#######################################################################
994
Yotam Harchol466b3212013-08-15 12:14:46 -0700995class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700996 def __init__(self, java_class):
997 self.java_class = java_class
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800998 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.dotless_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700999 name=java_class.c_name[3:])
Andreas Wundsamc8912c12013-11-15 13:44:48 -08001000 glob_file_name = "of{version}/{name}__*.data".format(version=java_class.version.dotless_version,
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -07001001 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -07001002 test_class_name = self.java_class.name + "Test"
1003 self.test_units = []
1004 if test_data.exists(first_data_file_name):
1005 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -07001006
Yotam Harchol466b3212013-08-15 12:14:46 -07001007 i = 1
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -07001008 for f in test_data.glob(glob_file_name):
1009 m = re.match(".*__(.*).data", f)
1010 if m:
1011 suffix = java_type.name_c_to_caps_camel(m.group(1))
1012 else:
1013 suffix = str(i)
1014 i += 1
1015 test_class_name = self.java_class.name + suffix + "Test"
1016 self.test_units.append(JavaUnitTest(java_class, f, test_class_name))
Andreas Wundsamf1949682013-09-23 14:48:31 -07001017
Yotam Harchol466b3212013-08-15 12:14:46 -07001018 @property
1019 def package(self):
1020 return self.java_class.package
1021
1022 @property
1023 def has_test_data(self):
1024 return len(self.test_units) > 0
1025
1026 @property
1027 def length(self):
1028 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -07001029
Yotam Harchol466b3212013-08-15 12:14:46 -07001030 def get_test_unit(self, i):
1031 return self.test_units[i]
1032
1033
1034class JavaUnitTest(object):
1035 def __init__(self, java_class, file_name=None, test_class_name=None):
1036 self.java_class = java_class
1037 if file_name is None:
Andreas Wundsamc8912c12013-11-15 13:44:48 -08001038 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.dotless_version,
Yotam Harchol466b3212013-08-15 12:14:46 -07001039 name=java_class.c_name[3:])
1040 else:
1041 self.data_file_name = file_name
1042 if test_class_name is None:
1043 self.test_class_name = self.java_class.name + "Test"
1044 else:
1045 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001046
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001047 @property
1048 def package(self):
1049 return self.java_class.package
1050
1051 @property
1052 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001053 return self.test_class_name
Yotam Harchol595c6442013-09-27 16:29:08 -07001054
1055 @property
1056 def interface(self):
1057 return self.java_class.interface
1058
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001059 @property
1060 def has_test_data(self):
1061 return test_data.exists(self.data_file_name)
1062
1063 @property
1064 @memoize
1065 def test_data(self):
1066 return test_data.read(self.data_file_name)
1067
1068
Andreas Wundsam27303462013-07-16 12:52:35 -07001069#######################################################################
1070### Enums
1071#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001072
Andreas Wundsam27303462013-07-16 12:52:35 -07001073class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001074 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001075 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001076
Rob Vaterlausfeee3712013-09-30 11:24:19 -07001077 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001078
Andreas Wundsam27303462013-07-16 12:52:35 -07001079 # Port_features has constants that start with digits
1080 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001081
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001082 self.version_enums = version_enum_map
1083
1084 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1085 for version, ir_enum in version_enum_map.items():
1086 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001087 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1088
Andreas Wundsam27303462013-07-16 12:52:35 -07001089 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001090 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001091
1092 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 -07001093 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001094
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001095 self.metadata = model.enum_metadata_map[self.name]
1096
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001097 def wire_type(self, version):
1098 ir_enum = self.version_enums[version]
1099 if "wire_type" in ir_enum.params:
1100 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1101 else:
1102 return java_type.u8
1103
1104 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001105 @memoize
1106 def is_bitmask(self):
1107 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1108
1109 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001110 def versions(self):
1111 return self.version_enums.keys()
1112
Andreas Wundsam27303462013-07-16 12:52:35 -07001113 @memoize
1114 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001115 res = find(lambda e: e.name == name, self.entries)
1116 if res:
1117 return res
1118 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001119 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1120
1121 @memoize
1122 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001123 res = find(lambda e: e.c_name == name, self.entries)
1124 if res:
1125 return res
1126 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001127 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1128
1129 @memoize
1130 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001131 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1132 if res:
1133 return res
1134 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001135 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1136
1137# values: Map JavaVersion->Value
1138class JavaEnumEntry(object):
1139 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001140 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001141 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1142 self.values = values
1143
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001144 @property
1145 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001146 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001147
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001148 def has_value(self, version):
1149 return version in self.values
1150
Andreas Wundsam27303462013-07-16 12:52:35 -07001151 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001152 return self.values[version]
1153
1154 def format_value(self, version):
1155 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001156 return res
1157
Andreas Wundsam27303462013-07-16 12:52:35 -07001158 def all_values(self, versions, not_present=None):
1159 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001160
1161 @property
1162 @memoize
1163 def masked_enum_group(self):
1164 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1165 return group
1166
1167 @property
1168 @memoize
1169 def is_mask(self):
1170 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])