blob: 8726632c1e0001ed0bdec40892805578a102e33a [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 Wundsam907c3612014-01-15 12:03:04 -080050
51def java_class_name(c_name):
52 return java_type.name_c_to_caps_camel(c_name) if c_name != "of_header" else "OFMessage"
53
Andreas Wundsam27303462013-07-16 12:52:35 -070054class JavaModel(object):
Andreas Wundsamf1949682013-09-23 14:48:31 -070055 # registry for enums that should not be generated
56 # set(${java_enum_name})
Andreas Wundsamacd57d52013-10-18 17:35:01 -070057 enum_blacklist = set(("OFDefinitions", "OFPortNo", "OFVlanId", "OFGroup"))
Andreas Wundsamf1949682013-09-23 14:48:31 -070058 # registry for enum *entry* that should not be generated
59 # map: ${java_enum_name} -> set(${java_entry_entry_name})
Andreas Wundsam43526532013-08-01 22:03:50 -070060 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 -070061 # registry of interfaces that should not be generated
62 # set(java_names)
Andreas Wundsambe168f72013-08-03 22:49:35 -070063 # OFUint structs are there for god-knows what in loci. We certainly don't need them.
64 interface_blacklist = set( ("OFUint8", "OFUint32",))
Andreas Wundsamf1949682013-09-23 14:48:31 -070065 # registry of interface properties that should not be generated
66 # map: $java_type -> set(java_name_property)
Rich Lane97fd13d2013-11-13 11:25:48 -080067 read_blacklist = defaultdict(lambda: set(),
68 OFExperimenter=set(('data','subtype')),
69 OFActionExperimenter=set(('data',)),
70 OFExperimenterStatsRequest=set(('data','subtype')),
Rich Lanef33f32f2013-11-18 15:49:54 -080071 OFExperimenterStatsReply=set(('data','subtype')),
72 OFInstructionExperimenter=set(('data',)))
Andreas Wundsamf1949682013-09-23 14:48:31 -070073 # map: $java_type -> set(java_name_property)
Rich Lane13730732013-12-03 13:05:19 -080074 write_blacklist = defaultdict(
75 lambda: set(),
76 OFOxm=set(('typeLen',)),
77 OFAction=set(('type',)),
78 OFInstruction=set(('type',)),
79 OFFlowMod=set(('command', )),
80 OFExperimenter=set(('data','subtype')),
81 OFActionExperimenter=set(('data',)),
82 OFBsnTlv=set(('type',)))
Andreas Wundsamf1949682013-09-23 14:48:31 -070083 # interfaces that are virtual
Andreas Wundsam001b1822013-08-02 22:25:55 -070084 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070085
Andreas Wundsamf1949682013-09-23 14:48:31 -070086 # Registry of nullable properties:
87 # ${java_class_name} -> set(${java_property_name})
88 nullable_map = defaultdict(lambda: set(),
89 )
90
91 # represents a subgroup of a bitmask enum that is actualy a normal enumerable within a masked part of the enum
92 # e.g., the flags STP.* in OF1.0 port state are bit mask entries, but instead enumerables according to the mask "STP_MASK"
93 # name: a name for the group
94 # mask: java name of the enum entry that defines the mask
95 # members: set of names of the members of the group
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -070096 MaskedEnumGroup = namedtuple("MaskedEnumGroup", ("name", "mask", "members"))
97
Andreas Wundsamf1949682013-09-23 14:48:31 -070098 # registry of MaskedEnumGroups (see above).
99 # map: ${java_enum_name}: tuple(MaskedEnumGroup)
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700100 masked_enum_groups = defaultdict(lambda: (),
Andreas Wundsamaebe5182013-09-24 13:01:07 -0700101 OFPortState = (MaskedEnumGroup("stp_flags", mask="STP_MASK", members=set(("STP_LISTEN", "STP_LEARN", "STP_FORWARD", "STP_BLOCK"))), ),
102 OFConfigFlags = (
103 MaskedEnumGroup("frag_flags", mask="FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
Andreas Wundsam376cef52013-09-24 13:52:18 -0700104 ),
105 OFTableConfig = (
106 MaskedEnumGroup("table_miss_flags", mask="TABLE_MISS_MASK", members=set(("TABLE_MISS_CONTROLLER", "TABLE_MISS_CONTINUE", "TABLE_MISS_DROP"))),
107 ),
Andreas Wundsam057540b2013-11-19 16:51:36 -0800108 OFGetConfigReply = (
109 MaskedEnumGroup("flags", mask="OFP_FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
110 ),
111 OFSetConfig = (
112 MaskedEnumGroup("flags", mask="OFP_FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
113 ),
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700114 )
115
Andreas Wundsamf1949682013-09-23 14:48:31 -0700116 # represents a metadata property associated with an EnumClass
117 # name:
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700118 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700119 """
120 represents a metadata property associated with an Enum Class
121 @param name name of metadata property
122 @param type java_type instance describing the type
123 @value: Generator function f(entry) that generates the value
124 """
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700125 @property
126 def variable_name(self):
127 return self.name[0].lower() + self.name[1:]
128
129 @property
130 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700131 prefix = "is" if self.type == java_type.boolean else "get"
132 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700133
Andreas Wundsamf1949682013-09-23 14:48:31 -0700134 """ Metadata container. """
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700135 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
136
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700137 def gen_port_speed(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700138 """ Generator function for OFortFeatures.PortSpeed"""
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700139 splits = enum_entry.name.split("_")
140 if len(splits)>=2:
141 m = re.match(r'\d+[MGTP]B', splits[1])
142 if m:
143 return "PortSpeed.SPEED_{}".format(splits[1])
144 return "PortSpeed.SPEED_NONE";
145
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700146 def gen_stp_state(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700147 """ Generator function for OFPortState.StpState"""
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700148 splits = enum_entry.name.split("_")
149 if len(splits)>=1:
150 if splits[0] == "STP":
151 return "true"
152 return "false"
153
Andreas Wundsamf1949682013-09-23 14:48:31 -0700154 # registry for metadata properties for enums
155 # map: ${java_enum_name}: OFEnumMetadata
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700156 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
Rob Vaterlausa049dee2013-09-18 16:18:37 -0700157 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
158 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700159 )
160
Andreas Wundsam27303462013-07-16 12:52:35 -0700161 @property
162 @memoize
163 def versions(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800164 return OrderedSet( JavaOFVersion(ir_version) for ir_version in OFVersions.target_versions)
Andreas Wundsam27303462013-07-16 12:52:35 -0700165
166 @property
167 @memoize
168 def interfaces(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800169 interfaces = [ JavaOFInterface(ir_class) for ir_class in loxi_globals.unified.classes ]
Andreas Wundsambe168f72013-08-03 22:49:35 -0700170 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
171
Andreas Wundsam27303462013-07-16 12:52:35 -0700172 return interfaces
173
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700174 @memoize
175 def interface_by_name(self, name):
176 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
177
Andreas Wundsam27303462013-07-16 12:52:35 -0700178 @property
179 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700180 def all_classes(self):
181 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
182
183 @property
184 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700185 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700186 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700187
188 for version in self.versions:
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800189 logger.info("version: {}".format(version.ir_version))
190 of_protocol = loxi_globals.ir[version.ir_version]
Andreas Wundsam27303462013-07-16 12:52:35 -0700191 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700192 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700193
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700194 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
195 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700196
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700197 # inelegant - need java name here
198 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700199 return enums
200
201 @memoize
202 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700203 res = find(lambda e: e.name == name, self.enums)
204 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700205 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700206 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700207
Andreas Wundsam5204de22013-07-30 11:34:45 -0700208 @property
209 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700210 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700211 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700212
213 factories = OrderedDict()
214
Andreas Wundsamd4b22692014-01-14 14:17:26 -0800215 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp", "OFErrorMsg", "OFActionId", "OFInstructionId", "OFBsnTlv")
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700216 for base_class in sub_factory_classes:
217 package = base_class[2:].lower()
218 remove_prefix = base_class[2].lower() + base_class[3:]
219
220 # HACK need to have a better way to deal with parameterized base classes
221 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
222
223 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
Andreas Wundsamd1ca4f92013-12-10 18:58:44 -0800224 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 -0700225
226 factories[""] = OFFactory(
227 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700228 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700229 remove_prefix="",
230 members=[], base_class="OFMessage", sub_factories=OrderedDict(
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700231 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ),
232 xid_generator=True)
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700233
234 for i in self.interfaces:
235 for n, factory in factories.items():
236 if n == "":
237 factory.members.append(i)
238 break
239 else:
240 super_class = self.interface_by_name(n)
241 if i.is_instance_of(super_class):
242 factory.members.append(i)
243 break
244 return factories.values()
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800245
Yotam Harchol595c6442013-09-27 16:29:08 -0700246 @memoize
247 def factory_of(self, interface):
248 for factory in self.of_factories:
249 if interface in factory.members:
250 return factory
251 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700252
253 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700254 """ return wether or not to generate implementation class clazz.
255 Now true for everything except OFTableModVer10.
256 @param clazz JavaOFClass instance
257 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700258 if clazz.interface.name.startswith("OFMatchV"):
259 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700260 elif clazz.name == "OFTableModVer10":
261 # tablemod ver 10 is a hack and has no oftype defined
262 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700263 if loxi_utils.class_is_message(clazz.interface.c_name):
264 return True
265 if loxi_utils.class_is_oxm(clazz.interface.c_name):
266 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700267 if loxi_utils.class_is_action(clazz.interface.c_name):
268 return True
269 if loxi_utils.class_is_instruction(clazz.interface.c_name):
270 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700271 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700272 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700273
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800274 @property
275 @memoize
276 def oxm_map(self):
277 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
278 return OrderedDict( (oxm.name, OxmMapEntry(type_name=oxm.member_by_name("value").java_type.public_type,
279 value=re.sub(r'^of_oxm_', r'', re.sub(r'_masked$', r'', oxm.ir_class.name)).upper(),
280 masked=oxm.ir_class.name.endswith("_masked")))
281 for oxm in self.interfaces if oxm.ir_class.is_subclassof("of_oxm") )
Andreas Wundsam5204de22013-07-30 11:34:45 -0700282
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700283class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories", "xid_generator"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700284 @property
285 def factory_classes(self):
286 return [ OFFactoryClass(
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800287 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.dotless_version),
288 name="{}Ver{}".format(self.name, version.dotless_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700289 interface=self,
290 version=version
291 ) for version in model.versions ]
292
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700293 def method_name(self, member, builder=True):
294 n = member.variable_name
295 if n.startswith(self.remove_prefix):
296 n = n[len(self.remove_prefix):]
297 n = n[0].lower() + n[1:]
298 if builder:
299 return "build" + n[0].upper() + n[1:]
300 else:
301 return n
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800302
Yotam Harchol595c6442013-09-27 16:29:08 -0700303 def of_version(self, version):
304 for fc in self.factory_classes:
305 if fc.version == version:
306 return fc
307 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700308
309OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700310class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
311 @property
312 def base_class(self):
313 return self.interface.base_class
314
315 @property
316 def versioned_base_class(self):
317 base_class_interface = model.interface_by_name(self.interface.base_class)
318 if base_class_interface and base_class_interface.has_version(self.version):
319 return base_class_interface.versioned_class(self.version)
320 else:
321 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700322
Andreas Wundsam27303462013-07-16 12:52:35 -0700323model = JavaModel()
324
325#######################################################################
326### OFVersion
327#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700328
329class JavaOFVersion(object):
330 """ Models a version of OpenFlow. contains methods to convert the internal
331 Loxi version to a java constant / a string """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800332 def __init__(self, ir_version):
333 assert isinstance(ir_version, OFVersion)
334 self.ir_version = ir_version
335 self.int_version = self.ir_version.wire_version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700336
337 @property
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800338 def dotless_version(self):
339 return self.ir_version.version.replace(".", "")
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700340
341 @property
342 def constant_version(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800343 return "OF_" + self.dotless_version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700344
Andreas Wundsam27303462013-07-16 12:52:35 -0700345 def __repr__(self):
346 return "JavaOFVersion(%d)" % self.int_version
347
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700348 def __str__(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800349 return self.ir_version.version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700350
Andreas Wundsam27303462013-07-16 12:52:35 -0700351 def __hash__(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800352 return hash(self.ir_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700353
354 def __eq__(self, other):
355 if other is None or type(self) != type(other):
356 return False
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800357 return (self.ir_version,) == (other.ir_version,)
Andreas Wundsam27303462013-07-16 12:52:35 -0700358
359#######################################################################
360### Interface
361#######################################################################
362
363class JavaOFInterface(object):
364 """ Models an OpenFlow Message class for the purpose of the java class.
365 Version agnostic, in contrast to the loxi_ir python model.
366 """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800367 def __init__(self, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700368 """"
369 @param c_name: loxi style name (e.g., of_flow_add)
370 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
371 """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800372 self.ir_class = ir_class
373 self.c_name = ir_class.name
374 self.version_map = { JavaOFVersion(v): c for v,c in ir_class.version_classes.items() }
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700375 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam907c3612014-01-15 12:03:04 -0800376 self.name = java_class_name(self.c_name)
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700377 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700378 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700379 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700380 # name for use in constants: FLOW_ADD
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800381 self.constant_name = self.c_name.upper().replace("OF_", "")
Andreas Wundsam27303462013-07-16 12:52:35 -0700382
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700383 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700384 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700385 if self.name != parent_interface:
386 self.parent_interface = parent_interface
387 else:
388 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700389
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700390 @property
391 @memoize
392 def all_parent_interfaces(self):
393 return [ "OFObject" ] + \
394 ([ self.parent_interface ] if self.parent_interface else [] )+ \
395 self.additional_parent_interfaces
396 @property
397 @memoize
398 def additional_parent_interfaces(self):
399 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
400 m = re.match(r'(.*)Request$', self.name)
401 if m:
402 reply_name = m.group(1) + "Reply"
403 if model.interface_by_name(reply_name):
404 return ["OFRequest<%s>" % reply_name ]
405 return []
406
407
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700408 def is_instance_of(self, other_class):
409 if self == other_class:
410 return True
411 parent = self.super_class
412 if parent is None:
413 return False
414 else:
415 return parent.is_instance_of(other_class)
416
417 @property
418 def super_class(self):
419 if not self.parent_interface:
420 return None
421 else:
422 return model.interface_by_name(self.parent_interface)
423
424
425 def inherited_declaration(self, type_spec="?"):
426 if self.type_annotation:
427 return "%s<%s>" % (self.name, type_spec)
428 else:
429 return "%s" % self.name
430
431 @property
432 def type_variable(self):
433 if self.type_annotation:
434 return "<T>"
435 else:
436 return "";
437
Andreas Wundsam27303462013-07-16 12:52:35 -0700438 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700439 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
Andreas Wundsam907c3612014-01-15 12:03:04 -0800440 # FIXME: This code could be cleaned up further. Maybe some of the exceptions
441 # here could be folded into ir, or the type arithmetic specified in a more general
442 # fashion
443 def calc_package(i):
444 if i.is_subclassof("of_error_msg"):
445 return "errormsg"
446 elif i.is_instanceof("of_action"):
447 return "action"
448 elif i.is_instanceof("of_action_id"):
449 return "actionid"
450 elif i.is_instanceof("of_instruction"):
451 return "instruction"
452 elif i.is_instanceof("of_instruction_id"):
453 return "instructionid"
454 elif i.is_instanceof("of_oxm"):
455 return "oxm"
456 elif i.is_instanceof("of_meter_band"):
457 return "meterband"
458 elif i.is_instanceof("of_queue_prop"):
459 return "queueprop"
460 elif i.is_instanceof("of_bsn_tlv"):
461 return "bsntlv"
462 else:
463 return ""
464
465 def calc_super_name(i):
466 if re.match('of_match_.*', i.name):
467 return "Match"
468 else:
469 ir_super_class = self.ir_class.superclass
470 return java_class_name(ir_super_class.name) if ir_super_class else ""
471
472 package = calc_package(self.ir_class)
473 super_name = calc_super_name(self.ir_class)
474
475 if self.name == "OFStatsRequest":
476 # stats_requests are special because of their type annotation
477 return (package, "OFMessage", "T extends OFStatsReply")
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800478 elif self.ir_class.is_subclassof('of_stats_request'):
Andreas Wundsam907c3612014-01-15 12:03:04 -0800479 # stats_request subclasses are special because of their type annotation
480 reply_name = re.sub(r'Request$', 'Reply', self.name)
481 super_type_annotation = "T" if self.ir_class.virtual else reply_name
482
483 type_annotation = "T extends {}".format(reply_name) if self.ir_class.virtual \
484 else ""
485
486 return (package, "{}<{}>".format(super_name, super_type_annotation),
487 type_annotation)
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700488 elif self.name == "OFOxm":
Andreas Wundsam907c3612014-01-15 12:03:04 -0800489 return (package, None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700490 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam907c3612014-01-15 12:03:04 -0800491 # look up type from member value for OFValueType type annotation
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800492 if self.member_by_name("value") is not None:
Andreas Wundsam907c3612014-01-15 12:03:04 -0800493 return (package, "OFOxm<%s>" % self.member_by_name("value").java_type.public_type, None)
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700494 else:
Andreas Wundsam907c3612014-01-15 12:03:04 -0800495 return (package, "OFOxm", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700496 else:
Andreas Wundsam907c3612014-01-15 12:03:04 -0800497 return (package, super_name, None)
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700498
499 @property
500 @memoize
501 def writeable_members(self):
502 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700503
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700504 @memoize
505 def member_by_name(self, name):
506 return find(lambda m: m.name == name, self.members)
507
Andreas Wundsam27303462013-07-16 12:52:35 -0700508 @property
509 @memoize
510 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700511 return self.ir_model_members + self.virtual_members
512
513 @property
514 @memoize
515 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700516 """return a list of all members to be exposed by this interface. Corresponds to
517 the union of the members of the vesioned classes without length, fieldlength
518 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700519 all_versions = []
520 member_map = collections.OrderedDict()
521
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800522 member_version_map = {}
Andreas Wundsam27303462013-07-16 12:52:35 -0700523 for (version, of_class) in self.version_map.items():
524 for of_member in of_class.members:
525 if isinstance(of_member, OFLengthMember) or \
526 isinstance(of_member, OFFieldLengthMember) or \
527 isinstance(of_member, OFPadMember):
528 continue
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800529 java_member = JavaMember.for_of_member(self, of_member)
Andreas Wundsam27303462013-07-16 12:52:35 -0700530 if of_member.name not in member_map:
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800531 member_map[of_member.name] = java_member
532 member_version_map[of_member.name] = version
533 else:
534 existing = member_map[of_member.name]
535
536 if existing.java_type.public_type != java_member.java_type.public_type:
537 raise Exception(
538 "Error constructing interface {}: type signatures do not match up between versions.\n"
539 " Member Name: {}\n"
540 " Existing: Version={}, Java={}, IR={}\n"
541 " New: Version={}, Java={}, IR={}"
542 .format(self.name, existing.name,
543 member_version_map[of_member.name], existing.java_type.public_type, existing.member.oftype,
544 version, java_member.java_type.public_type, java_member.member.oftype)
545 )
Andreas Wundsam27303462013-07-16 12:52:35 -0700546
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700547 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 -0700548
549 @property
550 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700551 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700552 if self.name == "OFOxm":
Andreas Wundsama0981022013-10-02 18:15:06 -0700553 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700554 JavaVirtualMember(self, "value", java_type.generic_t),
555 JavaVirtualMember(self, "mask", java_type.generic_t),
556 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
557 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800558 JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype("T"))
Andreas Wundsama0981022013-10-02 18:15:06 -0700559 ]
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800560 elif self.ir_class.is_subclassof("of_oxm"):
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800561 value = find(lambda m: m.name=="value", self.ir_model_members)
562 if value:
563 field_type = java_type.make_match_field_jtype(value.java_type.public_type)
564 else:
565 field_type = java_type.make_match_field_jtype()
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700566
Andreas Wundsama0981022013-10-02 18:15:06 -0700567 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700568 JavaVirtualMember(self, "matchField", field_type),
569 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800570 JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype(value.java_type.public_type),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800571 custom_template=lambda builder: "OFOxm{}_getCanonical.java".format(".Builder" if builder else "")),
Andreas Wundsama0981022013-10-02 18:15:06 -0700572 ]
573 if not find(lambda x: x.name == "mask", self.ir_model_members):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800574 virtual_members.append(
575 JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type))
Andreas Wundsama0981022013-10-02 18:15:06 -0700576
577 if not find(lambda m: m.name == "version", self.ir_model_members):
578 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version))
579
580 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700581
582 @property
583 @memoize
584 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700585 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700586 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 -0700587
588 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700589 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700590 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700591 return len(self.all_versions) == len(model.versions)
592
593 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700594 @memoize
595 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700596 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700597 return self.version_map.keys()
598
Andreas Wundsam5204de22013-07-30 11:34:45 -0700599 def has_version(self, version):
600 return version in self.version_map
601
Andreas Wundsam27303462013-07-16 12:52:35 -0700602 def versioned_class(self, version):
603 return JavaOFClass(self, version, self.version_map[version])
604
605 @property
606 @memoize
607 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700608 return [ self.versioned_class(version) for version in self.all_versions ]
609
610#######################################################################
611### (Versioned) Classes
612#######################################################################
613
614class JavaOFClass(object):
615 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700616 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700617 """
618 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700619 """
620 @param interface JavaOFInterface instance of the parent interface
621 @param version JavaOFVersion
622 @param ir_class OFClass from loxi_ir
623 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700624 self.interface = interface
625 self.ir_class = ir_class
626 self.c_name = self.ir_class.name
627 self.version = version
628 self.constant_name = self.c_name.upper().replace("OF_", "")
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800629 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.dotless_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700630 self.generated = False
631
632 @property
633 @memoize
634 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700635 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700636
637 @property
638 def name(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800639 return "%sVer%s" % (self.interface.name, self.version.dotless_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700640
641 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700642 def variable_name(self):
Andreas Wundsam781d99f2013-10-23 15:25:56 -0700643 return self.name[2].lower() + self.name[3:]
Andreas Wundsam5204de22013-07-30 11:34:45 -0700644
645 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700646 def length(self):
647 if self.is_fixed_length:
648 return self.min_length
649 else:
650 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
651
652 @property
653 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700654 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800655 return self.ir_class.base_length
Andreas Wundsam27303462013-07-16 12:52:35 -0700656
657 @property
658 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700659 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800660 return self.ir_class.is_fixed_length and not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700661
662 def all_properties(self):
663 return self.interface.members
664
Andreas Wundsam27303462013-07-16 12:52:35 -0700665 @property
666 @memoize
667 def data_members(self):
668 return [ prop for prop in self.members if prop.is_data ]
669
670 @property
671 @memoize
672 def fixed_value_members(self):
673 return [ prop for prop in self.members if prop.is_fixed_value ]
674
675 @property
676 @memoize
677 def public_members(self):
678 return [ prop for prop in self.members if prop.is_public ]
679
680 @property
681 @memoize
682 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700683 return self.ir_model_members + self.virtual_members
684
685 @property
Andreas Wundsama0981022013-10-02 18:15:06 -0700686 @memoize
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700687 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700688 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700689 return tuple(members)
690
691 @property
692 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700693 virtual_members = []
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800694 if self.ir_class.is_subclassof("of_oxm"):
695 value_member = find(lambda m: m.name, self.ir_model_members)
696 if value_member:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700697 oxm_entry = model.oxm_map[self.interface.name]
Andreas Wundsama0981022013-10-02 18:15:06 -0700698 virtual_members += [
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800699 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 -0700700 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800701 ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700702 else:
Andreas Wundsama0981022013-10-02 18:15:06 -0700703 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700704 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
705 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800706 ]
Andreas Wundsama0981022013-10-02 18:15:06 -0700707 if not find(lambda m: m.name == "version", self.ir_model_members):
708 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version, "OFVersion.%s" % self.version.constant_version))
709
710 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700711
Andreas Wundsam661a2222013-11-05 17:18:59 -0800712 @memoize
713 def member_by_name(self, name):
714 return find(lambda m: m.name == name, self.members)
715
Andreas Wundsam27303462013-07-16 12:52:35 -0700716 def all_versions(self):
717 return [ JavaOFVersion(int_version)
718 for int_version in of_g.unified[self.c_name]
719 if int_version != 'union' and int_version != 'object_id' ]
720
721 def version_is_inherited(self, version):
722 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
723
724 def inherited_from(self, version):
725 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
726
727 @property
728 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700729 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
730
731 @property
732 def discriminator(self):
733 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700734
735 @property
736 def is_extension(self):
737 return type_maps.message_is_extension(self.c_name, -1)
738
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700739 @property
740 def align(self):
741 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
742
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700743 @property
Andreas Wundsam5da68512013-10-22 22:18:00 -0700744 def length_includes_align(self):
745 return self.ir_class.params['length_includes_align'] == "True" if 'length_includes_align' in self.ir_class.params else False
746
747 @property
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700748 @memoize
749 def superclass(self):
750 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
751
752 @property
753 @memoize
754 def subclasses(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800755 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass
756 and c.ir_class.superclass.name == self.c_name ]
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700757
Andreas Wundsam27303462013-07-16 12:52:35 -0700758#######################################################################
759### Member
760#######################################################################
761
762
763class JavaMember(object):
764 """ Models a property (member) of an openflow class. """
765 def __init__(self, msg, name, java_type, member):
766 self.msg = msg
767 self.name = name
768 self.java_type = java_type
769 self.member = member
770 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700771
772 @property
773 def title_name(self):
774 return self.name[0].upper() + self.name[1:]
775
776 @property
777 def constant_name(self):
778 return self.c_name.upper()
779
780 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700781 def getter_name(self):
782 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
783
784 @property
785 def setter_name(self):
786 return "set" + self.title_name
787
788 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700789 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700790 if self.is_fixed_value:
791 return self.constant_name
792 else:
793 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700794
795 @property
796 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700797 if self.is_fixed_value:
798 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700799 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700800 default = self.java_type.default_op(self.msg.version)
801 if default == "null" and not self.is_nullable:
802 return None
803 else:
804 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700805
806 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700807 def enum_value(self):
808 if self.name == "version":
809 return "OFVersion.%s" % self.msg.version.constant_version
810
811 java_type = self.java_type.public_type;
812 try:
813 global model
814 enum = model.enum_by_name(java_type)
815 entry = enum.entry_by_version_value(self.msg.version, self.value)
816 return "%s.%s" % ( enum.name, entry.name)
817 except KeyError, e:
Andreas Wundsamaa8a9182013-11-19 09:45:01 -0800818 logger.debug("No enum found", e)
Andreas Wundsam27303462013-07-16 12:52:35 -0700819 return self.value
820
821 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700822 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700823 return isinstance(self.member, OFPadMember)
824
825 def is_type_value(self, version=None):
826 if(version==None):
827 return any(self.is_type_value(version) for version in self.msg.all_versions)
828 try:
829 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
830 except:
831 return False
832
833 @property
834 def is_field_length_value(self):
835 return isinstance(self.member, OFFieldLengthMember)
836
837 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700838 def is_discriminator(self):
839 return isinstance(self.member, OFDiscriminatorMember)
840
841 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700842 def is_length_value(self):
843 return isinstance(self.member, OFLengthMember)
844
845 @property
846 def is_public(self):
847 return not (self.is_pad or self.is_length_value)
848
849 @property
850 def is_data(self):
851 return isinstance(self.member, OFDataMember) and self.name != "version"
852
853 @property
854 def is_fixed_value(self):
855 return hasattr(self.member, "value") or self.name == "version" \
856 or ( self.name == "length" and self.msg.is_fixed_length) \
857 or ( self.name == "len" and self.msg.is_fixed_length)
858
859 @property
860 def value(self):
861 if self.name == "version":
862 return self.msg.version.int_version
863 elif self.name == "length" or self.name == "len":
864 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700865 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700866 return self.java_type.format_value(self.member.value)
867
868 @property
869 def priv_value(self):
870 if self.name == "version":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700871 return self.java_type.format_value(self.msg.version.int_version, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700872 elif self.name == "length" or self.name == "len":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700873 return self.java_type.format_value(self.msg.length, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700874 else:
875 return self.java_type.format_value(self.member.value, pub_type=False)
876
Andreas Wundsam27303462013-07-16 12:52:35 -0700877
878 @property
879 def is_writeable(self):
880 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
881
882 def get_type_value_info(self, version):
883 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700884
885 @property
886 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700887 if hasattr(self.member, "length"):
888 return self.member.length
889 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700890 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700891 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700892
893 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700894 def for_of_member(java_class, member):
895 if isinstance(member, OFPadMember):
896 return JavaMember(None, "", None, member)
897 else:
898 if member.name == 'len':
899 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700900 elif member.name == 'value_mask':
901 name = 'mask'
Andreas Wundsamacd57d52013-10-18 17:35:01 -0700902 elif member.name == 'group_id':
903 name = 'group'
Andreas Wundsam27303462013-07-16 12:52:35 -0700904 else:
905 name = java_type.name_c_to_camel(member.name)
906 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
907 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700908
909 @property
910 def is_universal(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800911 for version, ir_class in self.msg.ir_class.version_classes.items():
912 if not ir_class.member_by_name(self.member.name):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700913 return False
914 return True
915
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700916 @property
917 def is_virtual(self):
918 return False
919
Andreas Wundsam27303462013-07-16 12:52:35 -0700920 def __hash__(self):
921 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700922
Andreas Wundsam27303462013-07-16 12:52:35 -0700923 def __eq__(self, other):
924 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700925 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700926 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700927
Andreas Wundsamf1949682013-09-23 14:48:31 -0700928 @property
929 def is_nullable(self):
930 return self.name in model.nullable_map[self.msg.name]
931
932
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700933class JavaVirtualMember(JavaMember):
934 """ 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 -0800935 def __init__(self, msg, name, java_type, value=None, custom_template=None):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700936 JavaMember.__init__(self, msg, name, java_type, member=None)
937 self._value = value
Andreas Wundsam4b8661f2013-11-05 17:17:28 -0800938 self.custom_template = custom_template
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700939
940 @property
941 def is_fixed_value(self):
942 return True
943
944 @property
945 def value(self):
946 return self._value
947
948 @property
949 def priv_value(self):
950 return self._value
951
952
953 @property
954 def is_universal(self):
955 return True
956
957 @property
958 def is_virtual(self):
959 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700960
961#######################################################################
962### Unit Test
963#######################################################################
964
Yotam Harchol466b3212013-08-15 12:14:46 -0700965class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700966 def __init__(self, java_class):
967 self.java_class = java_class
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800968 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.dotless_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700969 name=java_class.c_name[3:])
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800970 glob_file_name = "of{version}/{name}__*.data".format(version=java_class.version.dotless_version,
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -0700971 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700972 test_class_name = self.java_class.name + "Test"
973 self.test_units = []
974 if test_data.exists(first_data_file_name):
975 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -0700976
Yotam Harchol466b3212013-08-15 12:14:46 -0700977 i = 1
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -0700978 for f in test_data.glob(glob_file_name):
979 m = re.match(".*__(.*).data", f)
980 if m:
981 suffix = java_type.name_c_to_caps_camel(m.group(1))
982 else:
983 suffix = str(i)
984 i += 1
985 test_class_name = self.java_class.name + suffix + "Test"
986 self.test_units.append(JavaUnitTest(java_class, f, test_class_name))
Andreas Wundsamf1949682013-09-23 14:48:31 -0700987
Yotam Harchol466b3212013-08-15 12:14:46 -0700988 @property
989 def package(self):
990 return self.java_class.package
991
992 @property
993 def has_test_data(self):
994 return len(self.test_units) > 0
995
996 @property
997 def length(self):
998 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -0700999
Yotam Harchol466b3212013-08-15 12:14:46 -07001000 def get_test_unit(self, i):
1001 return self.test_units[i]
1002
1003
1004class JavaUnitTest(object):
1005 def __init__(self, java_class, file_name=None, test_class_name=None):
1006 self.java_class = java_class
1007 if file_name is None:
Andreas Wundsamc8912c12013-11-15 13:44:48 -08001008 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.dotless_version,
Yotam Harchol466b3212013-08-15 12:14:46 -07001009 name=java_class.c_name[3:])
1010 else:
1011 self.data_file_name = file_name
1012 if test_class_name is None:
1013 self.test_class_name = self.java_class.name + "Test"
1014 else:
1015 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001016
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001017 @property
1018 def package(self):
1019 return self.java_class.package
1020
1021 @property
1022 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001023 return self.test_class_name
Yotam Harchol595c6442013-09-27 16:29:08 -07001024
1025 @property
1026 def interface(self):
1027 return self.java_class.interface
1028
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001029 @property
1030 def has_test_data(self):
1031 return test_data.exists(self.data_file_name)
1032
1033 @property
1034 @memoize
1035 def test_data(self):
1036 return test_data.read(self.data_file_name)
1037
1038
Andreas Wundsam27303462013-07-16 12:52:35 -07001039#######################################################################
1040### Enums
1041#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001042
Andreas Wundsam27303462013-07-16 12:52:35 -07001043class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001044 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001045 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001046
Rob Vaterlausfeee3712013-09-30 11:24:19 -07001047 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001048
Andreas Wundsam27303462013-07-16 12:52:35 -07001049 # Port_features has constants that start with digits
1050 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001051
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001052 self.version_enums = version_enum_map
1053
1054 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1055 for version, ir_enum in version_enum_map.items():
1056 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001057 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1058
Andreas Wundsam27303462013-07-16 12:52:35 -07001059 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001060 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001061
1062 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 -07001063 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001064
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001065 self.metadata = model.enum_metadata_map[self.name]
1066
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001067 def wire_type(self, version):
1068 ir_enum = self.version_enums[version]
1069 if "wire_type" in ir_enum.params:
1070 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1071 else:
1072 return java_type.u8
1073
1074 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001075 @memoize
1076 def is_bitmask(self):
1077 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1078
1079 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001080 def versions(self):
1081 return self.version_enums.keys()
1082
Andreas Wundsam27303462013-07-16 12:52:35 -07001083 @memoize
1084 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001085 res = find(lambda e: e.name == name, self.entries)
1086 if res:
1087 return res
1088 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001089 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1090
1091 @memoize
1092 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001093 res = find(lambda e: e.c_name == name, self.entries)
1094 if res:
1095 return res
1096 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001097 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1098
1099 @memoize
1100 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001101 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1102 if res:
1103 return res
1104 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001105 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1106
1107# values: Map JavaVersion->Value
1108class JavaEnumEntry(object):
1109 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001110 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001111 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1112 self.values = values
1113
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001114 @property
1115 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001116 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001117
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001118 def has_value(self, version):
1119 return version in self.values
1120
Andreas Wundsam27303462013-07-16 12:52:35 -07001121 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001122 return self.values[version]
1123
1124 def format_value(self, version):
1125 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001126 return res
1127
Andreas Wundsam27303462013-07-16 12:52:35 -07001128 def all_values(self, versions, not_present=None):
1129 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001130
1131 @property
1132 @memoize
1133 def masked_enum_group(self):
1134 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1135 return group
1136
1137 @property
1138 @memoize
1139 def is_mask(self):
1140 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])