blob: f90c1f213b165fd15ac2e49bc21eaee39da990f1 [file] [log] [blame]
Andreas Wundsam27303462013-07-16 12:52:35 -07001# Copyright 2013, Big Switch Networks, Inc.
2#
3# LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4# the following special exception:
5#
6# LOXI Exception
7#
8# As a special exception to the terms of the EPL, you may distribute libraries
9# generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10# that copyright and licensing notices generated by LoxiGen are not altered or removed
11# from the LoxiGen Libraries and the notice provided below is (i) included in
12# the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13# documentation for the LoxiGen Libraries, if distributed in binary form.
14#
15# Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16#
17# You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18# a copy of the EPL at:
19#
20# http://www.eclipse.org/legal/epl-v10.html
21#
22# Unless required by applicable law or agreed to in writing, software
23# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25# EPL for the specific language governing permissions and limitations
26# under the EPL.
27
Andreas Wundsam40e14f72013-05-06 14:49:08 -070028# Prototype of an Intermediate Object model for the java code generator
29# A lot of this stuff could/should probably be merged with the python utilities
30
Andreas Wundsam27303462013-07-16 12:52:35 -070031import collections
Andreas Wundsam5204de22013-07-30 11:34:45 -070032from collections import namedtuple, defaultdict, OrderedDict
Andreas Wundsam27303462013-07-16 12:52:35 -070033import logging
Andreas Wundsam40e14f72013-05-06 14:49:08 -070034import os
35import pdb
36import re
37
Andreas Wundsam5204de22013-07-30 11:34:45 -070038from generic_utils import find, memoize, OrderedSet, OrderedDefaultDict
Andreas Wundsamc8912c12013-11-15 13:44:48 -080039from loxi_globals import OFVersions
40import loxi_globals
Andreas Wundsam27303462013-07-16 12:52:35 -070041from loxi_ir import *
Andreas Wundsam5204de22013-07-30 11:34:45 -070042import loxi_utils.loxi_utils as loxi_utils
Andreas Wundsam5204de22013-07-30 11:34:45 -070043import test_data
Andreas Wundsam40e14f72013-05-06 14:49:08 -070044
Andreas Wundsam27303462013-07-16 12:52:35 -070045import java_gen.java_type as java_type
Andreas Wundsame0d52be2013-08-22 07:52:13 -070046from java_gen.java_type import erase_type_annotation
Andreas Wundsam40e14f72013-05-06 14:49:08 -070047
Andreas Wundsamc8912c12013-11-15 13:44:48 -080048logger = logging.getLogger(__name__)
49
Andreas Wundsam27303462013-07-16 12:52:35 -070050class JavaModel(object):
Andreas Wundsamf1949682013-09-23 14:48:31 -070051 # registry for enums that should not be generated
52 # set(${java_enum_name})
Andreas Wundsamacd57d52013-10-18 17:35:01 -070053 enum_blacklist = set(("OFDefinitions", "OFPortNo", "OFVlanId", "OFGroup"))
Andreas Wundsamf1949682013-09-23 14:48:31 -070054 # registry for enum *entry* that should not be generated
55 # map: ${java_enum_name} -> set(${java_entry_entry_name})
Andreas Wundsam43526532013-08-01 22:03:50 -070056 enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
Andreas Wundsamf1949682013-09-23 14:48:31 -070057
58 # registry of interfaces that should not be generated
59 # set(java_names)
Andreas Wundsambe168f72013-08-03 22:49:35 -070060 # OFUint structs are there for god-knows what in loci. We certainly don't need them.
61 interface_blacklist = set( ("OFUint8", "OFUint32",))
Andreas Wundsamf1949682013-09-23 14:48:31 -070062 # registry of interface properties that should not be generated
63 # map: $java_type -> set(java_name_property)
Rich Lane97fd13d2013-11-13 11:25:48 -080064 read_blacklist = defaultdict(lambda: set(),
65 OFExperimenter=set(('data','subtype')),
66 OFActionExperimenter=set(('data',)),
67 OFExperimenterStatsRequest=set(('data','subtype')),
68 OFExperimenterStatsReply=set(('data','subtype')))
Andreas Wundsamf1949682013-09-23 14:48:31 -070069 # map: $java_type -> set(java_name_property)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070070 write_blacklist = defaultdict(lambda: set(), OFOxm=set(('typeLen',)), OFAction=set(('type',)), OFInstruction=set(('type',)), OFFlowMod=set(('command', )), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
Andreas Wundsamf1949682013-09-23 14:48:31 -070071 # interfaces that are virtual
Andreas Wundsam001b1822013-08-02 22:25:55 -070072 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070073
Andreas Wundsamf1949682013-09-23 14:48:31 -070074 # Registry of nullable properties:
75 # ${java_class_name} -> set(${java_property_name})
76 nullable_map = defaultdict(lambda: set(),
77 )
78
79 # represents a subgroup of a bitmask enum that is actualy a normal enumerable within a masked part of the enum
80 # e.g., the flags STP.* in OF1.0 port state are bit mask entries, but instead enumerables according to the mask "STP_MASK"
81 # name: a name for the group
82 # mask: java name of the enum entry that defines the mask
83 # members: set of names of the members of the group
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -070084 MaskedEnumGroup = namedtuple("MaskedEnumGroup", ("name", "mask", "members"))
85
Andreas Wundsamf1949682013-09-23 14:48:31 -070086 # registry of MaskedEnumGroups (see above).
87 # map: ${java_enum_name}: tuple(MaskedEnumGroup)
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -070088 masked_enum_groups = defaultdict(lambda: (),
Andreas Wundsamaebe5182013-09-24 13:01:07 -070089 OFPortState = (MaskedEnumGroup("stp_flags", mask="STP_MASK", members=set(("STP_LISTEN", "STP_LEARN", "STP_FORWARD", "STP_BLOCK"))), ),
90 OFConfigFlags = (
91 MaskedEnumGroup("frag_flags", mask="FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
Andreas Wundsam376cef52013-09-24 13:52:18 -070092 ),
93 OFTableConfig = (
94 MaskedEnumGroup("table_miss_flags", mask="TABLE_MISS_MASK", members=set(("TABLE_MISS_CONTROLLER", "TABLE_MISS_CONTINUE", "TABLE_MISS_DROP"))),
95 ),
Andreas Wundsam057540b2013-11-19 16:51:36 -080096 OFGetConfigReply = (
97 MaskedEnumGroup("flags", mask="OFP_FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
98 ),
99 OFSetConfig = (
100 MaskedEnumGroup("flags", mask="OFP_FRAG_MASK", members=set(("FRAG_NORMAL", "FRAG_DROP", "FRAG_REASM"))),
101 ),
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -0700102 )
103
Andreas Wundsamf1949682013-09-23 14:48:31 -0700104 # represents a metadata property associated with an EnumClass
105 # name:
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700106 class OFEnumPropertyMetadata(namedtuple("OFEnumPropertyMetadata", ("name", "type", "value"))):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700107 """
108 represents a metadata property associated with an Enum Class
109 @param name name of metadata property
110 @param type java_type instance describing the type
111 @value: Generator function f(entry) that generates the value
112 """
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700113 @property
114 def variable_name(self):
115 return self.name[0].lower() + self.name[1:]
116
117 @property
118 def getter_name(self):
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700119 prefix = "is" if self.type == java_type.boolean else "get"
120 return prefix+self.name
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700121
Andreas Wundsamf1949682013-09-23 14:48:31 -0700122 """ Metadata container. """
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700123 OFEnumMetadata = namedtuple("OFEnumMetadata", ("properties", "to_string"))
124
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700125 def gen_port_speed(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700126 """ Generator function for OFortFeatures.PortSpeed"""
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700127 splits = enum_entry.name.split("_")
128 if len(splits)>=2:
129 m = re.match(r'\d+[MGTP]B', splits[1])
130 if m:
131 return "PortSpeed.SPEED_{}".format(splits[1])
132 return "PortSpeed.SPEED_NONE";
133
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700134 def gen_stp_state(enum_entry):
Andreas Wundsamf1949682013-09-23 14:48:31 -0700135 """ Generator function for OFPortState.StpState"""
Rob Vaterlausbda9ce62013-09-17 14:45:48 -0700136 splits = enum_entry.name.split("_")
137 if len(splits)>=1:
138 if splits[0] == "STP":
139 return "true"
140 return "false"
141
Andreas Wundsamf1949682013-09-23 14:48:31 -0700142 # registry for metadata properties for enums
143 # map: ${java_enum_name}: OFEnumMetadata
Rob Vaterlaus6035bf52013-09-17 19:32:38 -0700144 enum_metadata_map = defaultdict(lambda: JavaModel.OFEnumMetadata((), None),
Rob Vaterlausa049dee2013-09-18 16:18:37 -0700145 OFPortFeatures = OFEnumMetadata((OFEnumPropertyMetadata("PortSpeed", java_type.port_speed, gen_port_speed),), None),
146 OFPortState = OFEnumMetadata((OFEnumPropertyMetadata("StpState", java_type.boolean, gen_stp_state),), None),
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700147 )
148
Andreas Wundsam27303462013-07-16 12:52:35 -0700149 @property
150 @memoize
151 def versions(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800152 return OrderedSet( JavaOFVersion(ir_version) for ir_version in OFVersions.target_versions)
Andreas Wundsam27303462013-07-16 12:52:35 -0700153
154 @property
155 @memoize
156 def interfaces(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800157 interfaces = [ JavaOFInterface(ir_class) for ir_class in loxi_globals.unified.classes ]
Andreas Wundsambe168f72013-08-03 22:49:35 -0700158 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
159
Andreas Wundsam27303462013-07-16 12:52:35 -0700160 return interfaces
161
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700162 @memoize
163 def interface_by_name(self, name):
164 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
165
Andreas Wundsam27303462013-07-16 12:52:35 -0700166 @property
167 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700168 def all_classes(self):
169 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
170
171 @property
172 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700173 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700174 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700175
176 for version in self.versions:
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800177 logger.info("version: {}".format(version.ir_version))
178 of_protocol = loxi_globals.ir[version.ir_version]
Andreas Wundsam27303462013-07-16 12:52:35 -0700179 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700180 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700181
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700182 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
183 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700184
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700185 # inelegant - need java name here
186 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700187 return enums
188
189 @memoize
190 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700191 res = find(lambda e: e.name == name, self.enums)
192 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700193 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700194 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700195
Andreas Wundsam5204de22013-07-30 11:34:45 -0700196 @property
197 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700198 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700199 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700200
201 factories = OrderedDict()
202
203 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
204 for base_class in sub_factory_classes:
205 package = base_class[2:].lower()
206 remove_prefix = base_class[2].lower() + base_class[3:]
207
208 # HACK need to have a better way to deal with parameterized base classes
209 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
210
211 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700212 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={}, xid_generator=False)
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700213
214 factories[""] = OFFactory(
215 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700216 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700217 remove_prefix="",
218 members=[], base_class="OFMessage", sub_factories=OrderedDict(
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700219 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ),
220 xid_generator=True)
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700221
222 for i in self.interfaces:
223 for n, factory in factories.items():
224 if n == "":
225 factory.members.append(i)
226 break
227 else:
228 super_class = self.interface_by_name(n)
229 if i.is_instance_of(super_class):
230 factory.members.append(i)
231 break
232 return factories.values()
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800233
Yotam Harchol595c6442013-09-27 16:29:08 -0700234 @memoize
235 def factory_of(self, interface):
236 for factory in self.of_factories:
237 if interface in factory.members:
238 return factory
239 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700240
241 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700242 """ return wether or not to generate implementation class clazz.
243 Now true for everything except OFTableModVer10.
244 @param clazz JavaOFClass instance
245 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700246 if clazz.interface.name.startswith("OFMatchV"):
247 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700248 elif clazz.name == "OFTableModVer10":
249 # tablemod ver 10 is a hack and has no oftype defined
250 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700251 if loxi_utils.class_is_message(clazz.interface.c_name):
252 return True
253 if loxi_utils.class_is_oxm(clazz.interface.c_name):
254 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700255 if loxi_utils.class_is_action(clazz.interface.c_name):
256 return True
257 if loxi_utils.class_is_instruction(clazz.interface.c_name):
258 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700259 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700260 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700261
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800262 @property
263 @memoize
264 def oxm_map(self):
265 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
266 return OrderedDict( (oxm.name, OxmMapEntry(type_name=oxm.member_by_name("value").java_type.public_type,
267 value=re.sub(r'^of_oxm_', r'', re.sub(r'_masked$', r'', oxm.ir_class.name)).upper(),
268 masked=oxm.ir_class.name.endswith("_masked")))
269 for oxm in self.interfaces if oxm.ir_class.is_subclassof("of_oxm") )
Andreas Wundsam5204de22013-07-30 11:34:45 -0700270
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700271class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories", "xid_generator"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700272 @property
273 def factory_classes(self):
274 return [ OFFactoryClass(
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800275 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.dotless_version),
276 name="{}Ver{}".format(self.name, version.dotless_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700277 interface=self,
278 version=version
279 ) for version in model.versions ]
280
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700281 def method_name(self, member, builder=True):
282 n = member.variable_name
283 if n.startswith(self.remove_prefix):
284 n = n[len(self.remove_prefix):]
285 n = n[0].lower() + n[1:]
286 if builder:
287 return "build" + n[0].upper() + n[1:]
288 else:
289 return n
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800290
Yotam Harchol595c6442013-09-27 16:29:08 -0700291 def of_version(self, version):
292 for fc in self.factory_classes:
293 if fc.version == version:
294 return fc
295 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700296
297OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700298class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
299 @property
300 def base_class(self):
301 return self.interface.base_class
302
303 @property
304 def versioned_base_class(self):
305 base_class_interface = model.interface_by_name(self.interface.base_class)
306 if base_class_interface and base_class_interface.has_version(self.version):
307 return base_class_interface.versioned_class(self.version)
308 else:
309 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700310
Andreas Wundsam27303462013-07-16 12:52:35 -0700311model = JavaModel()
312
313#######################################################################
314### OFVersion
315#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700316
317class JavaOFVersion(object):
318 """ Models a version of OpenFlow. contains methods to convert the internal
319 Loxi version to a java constant / a string """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800320 def __init__(self, ir_version):
321 assert isinstance(ir_version, OFVersion)
322 self.ir_version = ir_version
323 self.int_version = self.ir_version.wire_version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700324
325 @property
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800326 def dotless_version(self):
327 return self.ir_version.version.replace(".", "")
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700328
329 @property
330 def constant_version(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800331 return "OF_" + self.dotless_version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700332
Andreas Wundsam27303462013-07-16 12:52:35 -0700333 def __repr__(self):
334 return "JavaOFVersion(%d)" % self.int_version
335
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700336 def __str__(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800337 return self.ir_version.version
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700338
Andreas Wundsam27303462013-07-16 12:52:35 -0700339 def __hash__(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800340 return hash(self.ir_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700341
342 def __eq__(self, other):
343 if other is None or type(self) != type(other):
344 return False
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800345 return (self.ir_version,) == (other.ir_version,)
Andreas Wundsam27303462013-07-16 12:52:35 -0700346
347#######################################################################
348### Interface
349#######################################################################
350
351class JavaOFInterface(object):
352 """ Models an OpenFlow Message class for the purpose of the java class.
353 Version agnostic, in contrast to the loxi_ir python model.
354 """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800355 def __init__(self, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700356 """"
357 @param c_name: loxi style name (e.g., of_flow_add)
358 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
359 """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800360 self.ir_class = ir_class
361 self.c_name = ir_class.name
362 self.version_map = { JavaOFVersion(v): c for v,c in ir_class.version_classes.items() }
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700363 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800364 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 -0700365 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700366 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700367 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700368 # name for use in constants: FLOW_ADD
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800369 self.constant_name = self.c_name.upper().replace("OF_", "")
Andreas Wundsam27303462013-07-16 12:52:35 -0700370
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700371 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700372 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700373 if self.name != parent_interface:
374 self.parent_interface = parent_interface
375 else:
376 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700377
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700378 @property
379 @memoize
380 def all_parent_interfaces(self):
381 return [ "OFObject" ] + \
382 ([ self.parent_interface ] if self.parent_interface else [] )+ \
383 self.additional_parent_interfaces
384 @property
385 @memoize
386 def additional_parent_interfaces(self):
387 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
388 m = re.match(r'(.*)Request$', self.name)
389 if m:
390 reply_name = m.group(1) + "Reply"
391 if model.interface_by_name(reply_name):
392 return ["OFRequest<%s>" % reply_name ]
393 return []
394
395
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700396 def is_instance_of(self, other_class):
397 if self == other_class:
398 return True
399 parent = self.super_class
400 if parent is None:
401 return False
402 else:
403 return parent.is_instance_of(other_class)
404
405 @property
406 def super_class(self):
407 if not self.parent_interface:
408 return None
409 else:
410 return model.interface_by_name(self.parent_interface)
411
412
413 def inherited_declaration(self, type_spec="?"):
414 if self.type_annotation:
415 return "%s<%s>" % (self.name, type_spec)
416 else:
417 return "%s" % self.name
418
419 @property
420 def type_variable(self):
421 if self.type_annotation:
422 return "<T>"
423 else:
424 return "";
425
Andreas Wundsam27303462013-07-16 12:52:35 -0700426 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700427 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
428 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
429 # model (note, that the loxi model is on versioned classes). Should check/infer the
430 # inheritance information from the versioned lox_ir classes.
Andreas Wundsamd6b0cb02013-09-28 18:55:56 -0700431 if re.match(r'OFStatsRequest$', self.name):
432 return ("", "OFMessage", "T extends OFStatsReply")
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800433 elif self.ir_class.is_subclassof('of_stats_request'):
Andreas Wundsam2c0a2d72013-11-15 15:16:36 -0800434 if self.ir_class.is_subclassof('of_bsn_stats_request'):
435 return ("", "OFBsnStatsRequest", None)
436 elif self.ir_class.is_subclassof('of_experimenter_stats_request'):
437 return ("", "OFExperimenterStatsRequest", None)
438 else:
439 return ("", "OFStatsRequest<{}>".format(re.sub(r'Request$', 'Reply', self.name)), None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800440 elif self.ir_class.is_subclassof('of_stats_reply'):
Andreas Wundsam2c0a2d72013-11-15 15:16:36 -0800441 if self.ir_class.is_subclassof('of_bsn_stats_reply'):
442 return ("", "OFBsnStatsReply", None)
443 elif self.ir_class.is_subclassof('of_experimenter_stats_reply'):
444 return ("", "OFExperimenterStatsReply", None)
445 else:
446 return ("", "OFStatsReply", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800447 elif self.ir_class.is_subclassof('of_error_msg'):
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700448 return ("", "OFErrorMsg", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800449 elif self.ir_class.is_subclassof('of_flow_mod'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700450 return ("", "OFFlowMod", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800451 elif self.ir_class.is_subclassof('of_group_mod'):
452 return ("", "OFGroupMod", None)
453 elif self.ir_class.is_subclassof('of_bsn_header'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700454 return ("", "OFBsnHeader", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800455 elif self.ir_class.is_subclassof('of_nicira_header'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700456 return ("", "OFNiciraHeader", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800457 elif self.ir_class.is_subclassof('of_experimenter'):
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700458 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700459 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700460 return ("", "Match", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800461 elif self.ir_class.is_message:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700462 return ("", "OFMessage", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800463 elif self.ir_class.is_action:
464 if self.ir_class.is_subclassof('of_action_bsn'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700465 return ("action", "OFActionBsn", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800466 elif self.ir_class.is_subclassof('of_action_nicira'):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700467 return ("action", "OFActionNicira", None)
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800468 elif self.ir_class.is_subclassof('of_action_experimenter'):
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700469 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700470 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700471 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700472 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700473 return ("", "OFBsnVport", None)
474 elif self.name == "OFOxm":
475 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700476 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800477 if self.member_by_name("value") is not None:
478 return ("oxm", "OFOxm<%s>" % self.member_by_name("value").java_type.public_type, None)
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700479 else:
480 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700481 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700482 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700483 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700484 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700485 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700486 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700487 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700488 return ("", "OFHelloElem", None)
Rich Lane26847562013-10-08 13:44:47 -0700489 elif loxi_utils.class_is_table_feature_prop(self.c_name):
490 return ("", "OFTableFeatureProp", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700491 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700492 return ("", None, None)
493
494 @property
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800495
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700496 @memoize
497 def writeable_members(self):
498 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700499
Andreas Wundsamcb17b232013-09-28 19:05:36 -0700500 @memoize
501 def member_by_name(self, name):
502 return find(lambda m: m.name == name, self.members)
503
Andreas Wundsam27303462013-07-16 12:52:35 -0700504 @property
505 @memoize
506 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700507 return self.ir_model_members + self.virtual_members
508
509 @property
510 @memoize
511 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700512 """return a list of all members to be exposed by this interface. Corresponds to
513 the union of the members of the vesioned classes without length, fieldlength
514 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700515 all_versions = []
516 member_map = collections.OrderedDict()
517
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800518 member_version_map = {}
Andreas Wundsam27303462013-07-16 12:52:35 -0700519 for (version, of_class) in self.version_map.items():
520 for of_member in of_class.members:
521 if isinstance(of_member, OFLengthMember) or \
522 isinstance(of_member, OFFieldLengthMember) or \
523 isinstance(of_member, OFPadMember):
524 continue
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800525 java_member = JavaMember.for_of_member(self, of_member)
Andreas Wundsam27303462013-07-16 12:52:35 -0700526 if of_member.name not in member_map:
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800527 member_map[of_member.name] = java_member
528 member_version_map[of_member.name] = version
529 else:
530 existing = member_map[of_member.name]
531
532 if existing.java_type.public_type != java_member.java_type.public_type:
533 raise Exception(
534 "Error constructing interface {}: type signatures do not match up between versions.\n"
535 " Member Name: {}\n"
536 " Existing: Version={}, Java={}, IR={}\n"
537 " New: Version={}, Java={}, IR={}"
538 .format(self.name, existing.name,
539 member_version_map[of_member.name], existing.java_type.public_type, existing.member.oftype,
540 version, java_member.java_type.public_type, java_member.member.oftype)
541 )
Andreas Wundsam27303462013-07-16 12:52:35 -0700542
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700543 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 -0700544
545 @property
546 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700547 virtual_members = []
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700548 if self.name == "OFOxm":
Andreas Wundsama0981022013-10-02 18:15:06 -0700549 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700550 JavaVirtualMember(self, "value", java_type.generic_t),
551 JavaVirtualMember(self, "mask", java_type.generic_t),
552 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
553 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800554 JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype("T"))
Andreas Wundsama0981022013-10-02 18:15:06 -0700555 ]
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800556 elif self.ir_class.is_subclassof("of_oxm"):
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800557 value = find(lambda m: m.name=="value", self.ir_model_members)
558 if value:
559 field_type = java_type.make_match_field_jtype(value.java_type.public_type)
560 else:
561 field_type = java_type.make_match_field_jtype()
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700562
Andreas Wundsama0981022013-10-02 18:15:06 -0700563 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700564 JavaVirtualMember(self, "matchField", field_type),
565 JavaVirtualMember(self, "masked", java_type.boolean),
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800566 JavaVirtualMember(self, "canonical", java_type.make_oxm_jtype(value.java_type.public_type),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800567 custom_template=lambda builder: "OFOxm{}_getCanonical.java".format(".Builder" if builder else "")),
Andreas Wundsama0981022013-10-02 18:15:06 -0700568 ]
569 if not find(lambda x: x.name == "mask", self.ir_model_members):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800570 virtual_members.append(
571 JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type))
Andreas Wundsama0981022013-10-02 18:15:06 -0700572
573 if not find(lambda m: m.name == "version", self.ir_model_members):
574 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version))
575
576 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700577
578 @property
579 @memoize
580 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700581 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700582 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 -0700583
584 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700585 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700586 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700587 return len(self.all_versions) == len(model.versions)
588
589 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700590 @memoize
591 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700592 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700593 return self.version_map.keys()
594
Andreas Wundsam5204de22013-07-30 11:34:45 -0700595 def has_version(self, version):
596 return version in self.version_map
597
Andreas Wundsam27303462013-07-16 12:52:35 -0700598 def versioned_class(self, version):
599 return JavaOFClass(self, version, self.version_map[version])
600
601 @property
602 @memoize
603 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700604 return [ self.versioned_class(version) for version in self.all_versions ]
605
606#######################################################################
607### (Versioned) Classes
608#######################################################################
609
610class JavaOFClass(object):
611 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700612 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700613 """
614 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700615 """
616 @param interface JavaOFInterface instance of the parent interface
617 @param version JavaOFVersion
618 @param ir_class OFClass from loxi_ir
619 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700620 self.interface = interface
621 self.ir_class = ir_class
622 self.c_name = self.ir_class.name
623 self.version = version
624 self.constant_name = self.c_name.upper().replace("OF_", "")
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800625 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.dotless_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700626 self.generated = False
627
628 @property
629 @memoize
630 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700631 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700632
633 @property
634 def name(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800635 return "%sVer%s" % (self.interface.name, self.version.dotless_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700636
637 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700638 def variable_name(self):
Andreas Wundsam781d99f2013-10-23 15:25:56 -0700639 return self.name[2].lower() + self.name[3:]
Andreas Wundsam5204de22013-07-30 11:34:45 -0700640
641 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700642 def length(self):
643 if self.is_fixed_length:
644 return self.min_length
645 else:
646 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
647
648 @property
649 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700650 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800651 return self.ir_class.base_length
Andreas Wundsam27303462013-07-16 12:52:35 -0700652
653 @property
654 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700655 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800656 return self.ir_class.is_fixed_length and not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700657
658 def all_properties(self):
659 return self.interface.members
660
Andreas Wundsam27303462013-07-16 12:52:35 -0700661 @property
662 @memoize
663 def data_members(self):
664 return [ prop for prop in self.members if prop.is_data ]
665
666 @property
667 @memoize
668 def fixed_value_members(self):
669 return [ prop for prop in self.members if prop.is_fixed_value ]
670
671 @property
672 @memoize
673 def public_members(self):
674 return [ prop for prop in self.members if prop.is_public ]
675
676 @property
677 @memoize
678 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700679 return self.ir_model_members + self.virtual_members
680
681 @property
Andreas Wundsama0981022013-10-02 18:15:06 -0700682 @memoize
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700683 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700684 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700685 return tuple(members)
686
687 @property
688 def virtual_members(self):
Andreas Wundsama0981022013-10-02 18:15:06 -0700689 virtual_members = []
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800690 if self.ir_class.is_subclassof("of_oxm"):
691 value_member = find(lambda m: m.name, self.ir_model_members)
692 if value_member:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700693 oxm_entry = model.oxm_map[self.interface.name]
Andreas Wundsama0981022013-10-02 18:15:06 -0700694 virtual_members += [
Andreas Wundsam83aebd32013-11-19 10:43:50 -0800695 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 -0700696 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800697 ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700698 else:
Andreas Wundsama0981022013-10-02 18:15:06 -0700699 virtual_members += [
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700700 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
701 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
Andreas Wundsam661a2222013-11-05 17:18:59 -0800702 ]
Andreas Wundsama0981022013-10-02 18:15:06 -0700703 if not find(lambda m: m.name == "version", self.ir_model_members):
704 virtual_members.append(JavaVirtualMember(self, "version", java_type.of_version, "OFVersion.%s" % self.version.constant_version))
705
706 return tuple(virtual_members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700707
Andreas Wundsam661a2222013-11-05 17:18:59 -0800708 @memoize
709 def member_by_name(self, name):
710 return find(lambda m: m.name == name, self.members)
711
Andreas Wundsam27303462013-07-16 12:52:35 -0700712 def all_versions(self):
713 return [ JavaOFVersion(int_version)
714 for int_version in of_g.unified[self.c_name]
715 if int_version != 'union' and int_version != 'object_id' ]
716
717 def version_is_inherited(self, version):
718 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
719
720 def inherited_from(self, version):
721 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
722
723 @property
724 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700725 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
726
727 @property
728 def discriminator(self):
729 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700730
731 @property
732 def is_extension(self):
733 return type_maps.message_is_extension(self.c_name, -1)
734
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700735 @property
736 def align(self):
737 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
738
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700739 @property
Andreas Wundsam5da68512013-10-22 22:18:00 -0700740 def length_includes_align(self):
741 return self.ir_class.params['length_includes_align'] == "True" if 'length_includes_align' in self.ir_class.params else False
742
743 @property
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700744 @memoize
745 def superclass(self):
746 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
747
748 @property
749 @memoize
750 def subclasses(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800751 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass
752 and c.ir_class.superclass.name == self.c_name ]
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700753
Andreas Wundsam27303462013-07-16 12:52:35 -0700754#######################################################################
755### Member
756#######################################################################
757
758
759class JavaMember(object):
760 """ Models a property (member) of an openflow class. """
761 def __init__(self, msg, name, java_type, member):
762 self.msg = msg
763 self.name = name
764 self.java_type = java_type
765 self.member = member
766 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700767
768 @property
769 def title_name(self):
770 return self.name[0].upper() + self.name[1:]
771
772 @property
773 def constant_name(self):
774 return self.c_name.upper()
775
776 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700777 def getter_name(self):
778 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
779
780 @property
781 def setter_name(self):
782 return "set" + self.title_name
783
784 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700785 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700786 if self.is_fixed_value:
787 return self.constant_name
788 else:
789 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700790
791 @property
792 def default_value(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700793 if self.is_fixed_value:
794 return self.enum_value
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700795 else:
Andreas Wundsam142dd2a2013-09-23 14:47:37 -0700796 default = self.java_type.default_op(self.msg.version)
797 if default == "null" and not self.is_nullable:
798 return None
799 else:
800 return default
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700801
802 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700803 def enum_value(self):
804 if self.name == "version":
805 return "OFVersion.%s" % self.msg.version.constant_version
806
807 java_type = self.java_type.public_type;
808 try:
809 global model
810 enum = model.enum_by_name(java_type)
811 entry = enum.entry_by_version_value(self.msg.version, self.value)
812 return "%s.%s" % ( enum.name, entry.name)
813 except KeyError, e:
Andreas Wundsamaa8a9182013-11-19 09:45:01 -0800814 logger.debug("No enum found", e)
Andreas Wundsam27303462013-07-16 12:52:35 -0700815 return self.value
816
817 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700818 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700819 return isinstance(self.member, OFPadMember)
820
821 def is_type_value(self, version=None):
822 if(version==None):
823 return any(self.is_type_value(version) for version in self.msg.all_versions)
824 try:
825 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
826 except:
827 return False
828
829 @property
830 def is_field_length_value(self):
831 return isinstance(self.member, OFFieldLengthMember)
832
833 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700834 def is_discriminator(self):
835 return isinstance(self.member, OFDiscriminatorMember)
836
837 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700838 def is_length_value(self):
839 return isinstance(self.member, OFLengthMember)
840
841 @property
842 def is_public(self):
843 return not (self.is_pad or self.is_length_value)
844
845 @property
846 def is_data(self):
847 return isinstance(self.member, OFDataMember) and self.name != "version"
848
849 @property
850 def is_fixed_value(self):
851 return hasattr(self.member, "value") or self.name == "version" \
852 or ( self.name == "length" and self.msg.is_fixed_length) \
853 or ( self.name == "len" and self.msg.is_fixed_length)
854
855 @property
856 def value(self):
857 if self.name == "version":
858 return self.msg.version.int_version
859 elif self.name == "length" or self.name == "len":
860 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700861 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700862 return self.java_type.format_value(self.member.value)
863
864 @property
865 def priv_value(self):
866 if self.name == "version":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700867 return self.java_type.format_value(self.msg.version.int_version, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700868 elif self.name == "length" or self.name == "len":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700869 return self.java_type.format_value(self.msg.length, pub_type=False)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700870 else:
871 return self.java_type.format_value(self.member.value, pub_type=False)
872
Andreas Wundsam27303462013-07-16 12:52:35 -0700873
874 @property
875 def is_writeable(self):
876 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
877
878 def get_type_value_info(self, version):
879 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700880
881 @property
882 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700883 if hasattr(self.member, "length"):
884 return self.member.length
885 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700886 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700887 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700888
889 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700890 def for_of_member(java_class, member):
891 if isinstance(member, OFPadMember):
892 return JavaMember(None, "", None, member)
893 else:
894 if member.name == 'len':
895 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700896 elif member.name == 'value_mask':
897 name = 'mask'
Andreas Wundsamacd57d52013-10-18 17:35:01 -0700898 elif member.name == 'group_id':
899 name = 'group'
Andreas Wundsam27303462013-07-16 12:52:35 -0700900 else:
901 name = java_type.name_c_to_camel(member.name)
902 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
903 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700904
905 @property
906 def is_universal(self):
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800907 for version, ir_class in self.msg.ir_class.version_classes.items():
908 if not ir_class.member_by_name(self.member.name):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700909 return False
910 return True
911
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700912 @property
913 def is_virtual(self):
914 return False
915
Andreas Wundsam27303462013-07-16 12:52:35 -0700916 def __hash__(self):
917 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700918
Andreas Wundsam27303462013-07-16 12:52:35 -0700919 def __eq__(self, other):
920 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700921 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700922 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700923
Andreas Wundsamf1949682013-09-23 14:48:31 -0700924 @property
925 def is_nullable(self):
926 return self.name in model.nullable_map[self.msg.name]
927
928
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700929class JavaVirtualMember(JavaMember):
930 """ 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 -0800931 def __init__(self, msg, name, java_type, value=None, custom_template=None):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700932 JavaMember.__init__(self, msg, name, java_type, member=None)
933 self._value = value
Andreas Wundsam4b8661f2013-11-05 17:17:28 -0800934 self.custom_template = custom_template
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700935
936 @property
937 def is_fixed_value(self):
938 return True
939
940 @property
941 def value(self):
942 return self._value
943
944 @property
945 def priv_value(self):
946 return self._value
947
948
949 @property
950 def is_universal(self):
951 return True
952
953 @property
954 def is_virtual(self):
955 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700956
957#######################################################################
958### Unit Test
959#######################################################################
960
Yotam Harchol466b3212013-08-15 12:14:46 -0700961class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700962 def __init__(self, java_class):
963 self.java_class = java_class
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800964 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.dotless_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700965 name=java_class.c_name[3:])
Andreas Wundsamc8912c12013-11-15 13:44:48 -0800966 glob_file_name = "of{version}/{name}__*.data".format(version=java_class.version.dotless_version,
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -0700967 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700968 test_class_name = self.java_class.name + "Test"
969 self.test_units = []
970 if test_data.exists(first_data_file_name):
971 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -0700972
Yotam Harchol466b3212013-08-15 12:14:46 -0700973 i = 1
Andreas Wundsamaa4f3cd2013-10-22 22:19:08 -0700974 for f in test_data.glob(glob_file_name):
975 m = re.match(".*__(.*).data", f)
976 if m:
977 suffix = java_type.name_c_to_caps_camel(m.group(1))
978 else:
979 suffix = str(i)
980 i += 1
981 test_class_name = self.java_class.name + suffix + "Test"
982 self.test_units.append(JavaUnitTest(java_class, f, test_class_name))
Andreas Wundsamf1949682013-09-23 14:48:31 -0700983
Yotam Harchol466b3212013-08-15 12:14:46 -0700984 @property
985 def package(self):
986 return self.java_class.package
987
988 @property
989 def has_test_data(self):
990 return len(self.test_units) > 0
991
992 @property
993 def length(self):
994 return len(self.test_units)
Andreas Wundsamf1949682013-09-23 14:48:31 -0700995
Yotam Harchol466b3212013-08-15 12:14:46 -0700996 def get_test_unit(self, i):
997 return self.test_units[i]
998
999
1000class JavaUnitTest(object):
1001 def __init__(self, java_class, file_name=None, test_class_name=None):
1002 self.java_class = java_class
1003 if file_name is None:
Andreas Wundsamc8912c12013-11-15 13:44:48 -08001004 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.dotless_version,
Yotam Harchol466b3212013-08-15 12:14:46 -07001005 name=java_class.c_name[3:])
1006 else:
1007 self.data_file_name = file_name
1008 if test_class_name is None:
1009 self.test_class_name = self.java_class.name + "Test"
1010 else:
1011 self.test_class_name = test_class_name
Andreas Wundsamf1949682013-09-23 14:48:31 -07001012
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001013 @property
1014 def package(self):
1015 return self.java_class.package
1016
1017 @property
1018 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -07001019 return self.test_class_name
Yotam Harchol595c6442013-09-27 16:29:08 -07001020
1021 @property
1022 def interface(self):
1023 return self.java_class.interface
1024
Andreas Wundsame916d6f2013-07-30 11:33:58 -07001025 @property
1026 def has_test_data(self):
1027 return test_data.exists(self.data_file_name)
1028
1029 @property
1030 @memoize
1031 def test_data(self):
1032 return test_data.read(self.data_file_name)
1033
1034
Andreas Wundsam27303462013-07-16 12:52:35 -07001035#######################################################################
1036### Enums
1037#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001038
Andreas Wundsam27303462013-07-16 12:52:35 -07001039class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001040 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -07001041 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -07001042
Rob Vaterlausfeee3712013-09-30 11:24:19 -07001043 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001044
Andreas Wundsam27303462013-07-16 12:52:35 -07001045 # Port_features has constants that start with digits
1046 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001047
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001048 self.version_enums = version_enum_map
1049
1050 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
1051 for version, ir_enum in version_enum_map.items():
1052 for ir_entry in ir_enum.entries:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001053 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
1054
Andreas Wundsam27303462013-07-16 12:52:35 -07001055 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001056 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -07001057
1058 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 -07001059 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001060
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001061 self.metadata = model.enum_metadata_map[self.name]
1062
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001063 def wire_type(self, version):
1064 ir_enum = self.version_enums[version]
1065 if "wire_type" in ir_enum.params:
1066 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1067 else:
1068 return java_type.u8
1069
1070 @property
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07001071 @memoize
1072 def is_bitmask(self):
1073 return any(ir_enum.is_bitmask for ir_enum in self.version_enums.values())
1074
1075 @property
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001076 def versions(self):
1077 return self.version_enums.keys()
1078
Andreas Wundsam27303462013-07-16 12:52:35 -07001079 @memoize
1080 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001081 res = find(lambda e: e.name == name, self.entries)
1082 if res:
1083 return res
1084 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001085 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1086
1087 @memoize
1088 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001089 res = find(lambda e: e.c_name == name, self.entries)
1090 if res:
1091 return res
1092 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001093 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1094
1095 @memoize
1096 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001097 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1098 if res:
1099 return res
1100 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001101 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1102
1103# values: Map JavaVersion->Value
1104class JavaEnumEntry(object):
1105 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001106 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001107 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1108 self.values = values
1109
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001110 @property
1111 def constructor_params(self):
Rob Vaterlaus6035bf52013-09-17 19:32:38 -07001112 return [ m.value(self) for m in self.enum.metadata.properties ]
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001113
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001114 def has_value(self, version):
1115 return version in self.values
1116
Andreas Wundsam27303462013-07-16 12:52:35 -07001117 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001118 return self.values[version]
1119
1120 def format_value(self, version):
1121 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001122 return res
1123
Andreas Wundsam27303462013-07-16 12:52:35 -07001124 def all_values(self, versions, not_present=None):
1125 return [ self.values[version] if version in self.values else not_present for version in versions ]
Andreas Wundsamc1acfcc2013-09-20 13:10:20 -07001126
1127 @property
1128 @memoize
1129 def masked_enum_group(self):
1130 group = find(lambda g: self.name in g.members, model.masked_enum_groups[self.enum.name])
1131 return group
1132
1133 @property
1134 @memoize
1135 def is_mask(self):
1136 return any(self.name == g.mask for g in model.masked_enum_groups[self.enum.name])