blob: a8824750acb04aa62bf2a2b1ef300f53b344727f [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 Wundsam27303462013-07-16 12:52:35 -070039import of_g
40from loxi_ir import *
Andreas Wundsam40e14f72013-05-06 14:49:08 -070041import loxi_front_end.type_maps as type_maps
Andreas Wundsam5204de22013-07-30 11:34:45 -070042import loxi_utils.loxi_utils as loxi_utils
Andreas Wundsam40e14f72013-05-06 14:49:08 -070043import py_gen.util as py_utils
Andreas Wundsam5204de22013-07-30 11:34:45 -070044import test_data
Andreas Wundsam40e14f72013-05-06 14:49:08 -070045
Andreas Wundsam27303462013-07-16 12:52:35 -070046import java_gen.java_type as java_type
Andreas Wundsame0d52be2013-08-22 07:52:13 -070047from java_gen.java_type import erase_type_annotation
Andreas Wundsam40e14f72013-05-06 14:49:08 -070048
Andreas Wundsam27303462013-07-16 12:52:35 -070049class JavaModel(object):
Andreas Wundsam43526532013-08-01 22:03:50 -070050 enum_blacklist = set(("OFDefinitions",))
51 enum_entry_blacklist = defaultdict(lambda: set(), OFFlowWildcards=set([ "NW_DST_BITS", "NW_SRC_BITS", "NW_SRC_SHIFT", "NW_DST_SHIFT" ]))
Andreas Wundsambe168f72013-08-03 22:49:35 -070052 # OFUint structs are there for god-knows what in loci. We certainly don't need them.
53 interface_blacklist = set( ("OFUint8", "OFUint32",))
Andreas Wundsamb1da3f62013-09-04 18:46:03 -070054 read_blacklist = defaultdict(lambda: set(), OFExperimenter=set(('data','subtype')), OFActionExperimenter=set(('data',)))
55 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 Wundsam001b1822013-08-02 22:25:55 -070056 virtual_interfaces = set(['OFOxm', 'OFInstruction', 'OFFlowMod', 'OFBsnVport' ])
Andreas Wundsam27303462013-07-16 12:52:35 -070057
Andreas Wundsam2be7da52013-08-22 07:34:25 -070058 OxmMapEntry = namedtuple("OxmMapEntry", ["type_name", "value", "masked" ])
Yotam Harchole5d92972013-08-22 14:18:36 -070059 oxm_map = { "OFOxmInPort": OxmMapEntry("OFPort", "IN_PORT", False),
60 "OFOxmInPortMasked": OxmMapEntry("OFPort", "IN_PORT", True),
61 "OFOxmInPhyPort": OxmMapEntry("OFPort", "IN_PHY_PORT", False),
62 "OFOxmInPhyPortMasked": OxmMapEntry("OFPort", "IN_PHY_PORT", True),
63 "OFOxmMetadata": OxmMapEntry("OFMetadata", "METADATA", False),
64 "OFOxmMetadataMasked": OxmMapEntry("OFMetadata", "METADATA", True),
65 "OFOxmEthDst": OxmMapEntry("MacAddress", "ETH_DST", False),
66 "OFOxmEthDstMasked": OxmMapEntry("MacAddress", "ETH_DST", True),
67 "OFOxmEthSrc": OxmMapEntry("MacAddress", "ETH_SRC", False),
68 "OFOxmEthSrcMasked": OxmMapEntry("MacAddress", "ETH_SRC", True),
69 "OFOxmEthType": OxmMapEntry("EthType", "ETH_TYPE", False),
70 "OFOxmEthTypeMasked": OxmMapEntry("EthType", "ETH_TYPE", True),
71 "OFOxmVlanVid": OxmMapEntry("VlanVid", "VLAN_VID", False),
72 "OFOxmVlanVidMasked": OxmMapEntry("VlanVid", "VLAN_VID", True),
73 "OFOxmVlanPcp": OxmMapEntry("VlanPcp", "VLAN_PCP", False),
74 "OFOxmVlanPcpMasked": OxmMapEntry("VlanPcp", "VLAN_PCP", True),
75 "OFOxmIpDscp": OxmMapEntry("IpDscp", "IP_DSCP", False),
76 "OFOxmIpDscpMasked": OxmMapEntry("IpDscp", "IP_DSCP", True),
77 "OFOxmIpEcn": OxmMapEntry("IpEcn", "IP_ECN", False),
78 "OFOxmIpEcnMasked": OxmMapEntry("IpEcn", "IP_ECN", True),
79 "OFOxmIpProto": OxmMapEntry("IpProtocol", "IP_PROTO", False),
80 "OFOxmIpProtoMasked": OxmMapEntry("IpProtocol", "IP_PROTO", True),
Yotam Harchola289d552013-09-16 10:10:40 -070081 "OFOxmIpv4Src": OxmMapEntry("IPv4Address", "IPV4_SRC", False),
82 "OFOxmIpv4SrcMasked": OxmMapEntry("IPv4Address", "IPV4_SRC", True),
83 "OFOxmIpv4Dst": OxmMapEntry("IPv4Address", "IPV4_DST", False),
84 "OFOxmIpv4DstMasked": OxmMapEntry("IPv4Address", "IPV4_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -070085 "OFOxmTcpSrc": OxmMapEntry("TransportPort", "TCP_SRC", False),
86 "OFOxmTcpSrcMasked": OxmMapEntry("TransportPort", "TCP_SRC", True),
87 "OFOxmTcpDst": OxmMapEntry("TransportPort", "TCP_DST", False),
88 "OFOxmTcpDstMasked": OxmMapEntry("TransportPort", "TCP_DST", True),
89 "OFOxmUdpSrc": OxmMapEntry("TransportPort", "UDP_SRC", False),
90 "OFOxmUdpSrcMasked": OxmMapEntry("TransportPort", "UDP_SRC", True),
91 "OFOxmUdpDst": OxmMapEntry("TransportPort", "UDP_DST", False),
92 "OFOxmUdpDstMasked": OxmMapEntry("TransportPort", "UDP_DST", True),
93 "OFOxmSctpSrc": OxmMapEntry("TransportPort", "SCTP_SRC", False),
94 "OFOxmSctpSrcMasked": OxmMapEntry("TransportPort", "SCTP_SRC", True),
95 "OFOxmSctpDst": OxmMapEntry("TransportPort", "SCTP_DST", False),
96 "OFOxmSctpDstMasked": OxmMapEntry("TransportPort", "SCTP_DST", True),
97 "OFOxmIcmpv4Type": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", False),
98 "OFOxmIcmpv4TypeMasked": OxmMapEntry("ICMPv4Type", "ICMPV4_TYPE", True),
99 "OFOxmIcmpv4Code": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", False),
100 "OFOxmIcmpv4CodeMasked": OxmMapEntry("ICMPv4Code", "ICMPV4_CODE", True),
101 "OFOxmArpOp": OxmMapEntry("ArpOpcode", "ARP_OP", False),
102 "OFOxmArpOpMasked": OxmMapEntry("ArpOpcode", "ARP_OP", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700103 "OFOxmArpSpa": OxmMapEntry("IPv4Address", "ARP_SPA", False),
104 "OFOxmArpSpaMasked": OxmMapEntry("IPv4Address", "ARP_SPA", True),
105 "OFOxmArpTpa": OxmMapEntry("IPv4Address", "ARP_TPA", False),
106 "OFOxmArpTpaMasked": OxmMapEntry("IPv4Address", "ARP_TPA", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700107 "OFOxmArpSha": OxmMapEntry("MacAddress", "ARP_SHA", False),
108 "OFOxmArpShaMasked": OxmMapEntry("MacAddress", "ARP_SHA", True),
109 "OFOxmArpTha": OxmMapEntry("MacAddress", "ARP_THA", False),
110 "OFOxmArpThaMasked": OxmMapEntry("MacAddress", "ARP_THA", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700111 "OFOxmIpv6Src": OxmMapEntry("IPv6Address", "IPV6_SRC", False),
112 "OFOxmIpv6SrcMasked": OxmMapEntry("IPv6Address", "IPV6_SRC", True),
113 "OFOxmIpv6Dst": OxmMapEntry("IPv6Address", "IPV6_DST", False),
114 "OFOxmIpv6DstMasked": OxmMapEntry("IPv6Address", "IPV6_DST", True),
Yotam Harchole5d92972013-08-22 14:18:36 -0700115 "OFOxmIpv6Flabel": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", False),
Yotam Harchola86e4252013-09-06 15:36:28 -0700116 "OFOxmIpv6FlabelMasked": OxmMapEntry("IPv6FlowLabel", "IPV6_FLABEL", True),
117 "OFOxmIcmpv6Type": OxmMapEntry("U8", "ICMPV6_TYPE", False),
118 "OFOxmIcmpv6TypeMasked": OxmMapEntry("U8", "ICMPV6_TYPE", True),
119 "OFOxmIcmpv6Code": OxmMapEntry("U8", "ICMPV6_CODE", False),
120 "OFOxmIcmpv6CodeMasked": OxmMapEntry("U8", "ICMPV6_CODE", True),
Yotam Harchola289d552013-09-16 10:10:40 -0700121 "OFOxmIpv6NdTarget": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", False),
122 "OFOxmIpv6NdTargetMasked": OxmMapEntry("IPv6Address", "IPV6_ND_TARGET", True),
Yotam Harchola86e4252013-09-06 15:36:28 -0700123 "OFOxmIpv6NdSll": OxmMapEntry("MacAddress", "IPV6_ND_SLL", False),
124 "OFOxmIpv6NdSllMasked": OxmMapEntry("MacAddress", "IPV6_ND_SLL", True),
125 "OFOxmIpv6NdTll": OxmMapEntry("MacAddress", "IPV6_ND_TLL", False),
126 "OFOxmIpv6NdTllMasked": OxmMapEntry("MacAddress", "IPV6_ND_TLL", True),
127 "OFOxmMplsLabel": OxmMapEntry("U32", "MPLS_LABEL", False),
128 "OFOxmMplsLabelMasked": OxmMapEntry("U32", "MPLS_LABEL", True),
129 "OFOxmMplsTc": OxmMapEntry("U8", "MPLS_TC", False),
130 "OFOxmMplsTcMasked": OxmMapEntry("U8", "MPLS_TC", True)
131 }
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700132
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700133 class OFEnumMetadata(namedtuple("OFEnumMetadata", ("name", "type", "value"))):
134 @property
135 def variable_name(self):
136 return self.name[0].lower() + self.name[1:]
137
138 @property
139 def getter_name(self):
140 return "get"+self.name
141
142 def gen_port_speed(enum_entry):
143 splits = enum_entry.name.split("_")
144 if len(splits)>=2:
145 m = re.match(r'\d+[MGTP]B', splits[1])
146 if m:
147 return "PortSpeed.SPEED_{}".format(splits[1])
148 return "PortSpeed.SPEED_NONE";
149
150 enum_metadata_map = defaultdict(lambda: (),
151 OFPortFeatures = ( OFEnumMetadata("PortSpeed", java_type.port_speed, gen_port_speed), )
152 )
153
Andreas Wundsam27303462013-07-16 12:52:35 -0700154 @property
155 @memoize
156 def versions(self):
157 return OrderedSet( JavaOFVersion(raw_version) for raw_version in of_g.target_version_list )
158
159 @property
160 @memoize
161 def interfaces(self):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700162 version_map_per_class = collections.OrderedDict()
Andreas Wundsam27303462013-07-16 12:52:35 -0700163
164 for raw_version, of_protocol in of_g.ir.items():
165 jversion = JavaOFVersion(of_protocol.wire_version)
166
167 for of_class in of_protocol.classes:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700168 if not of_class.name in version_map_per_class:
169 version_map_per_class[of_class.name] = collections.OrderedDict()
170
Andreas Wundsam27303462013-07-16 12:52:35 -0700171 version_map_per_class[of_class.name][jversion] = of_class
172
173 interfaces = []
174 for class_name, version_map in version_map_per_class.items():
175 interfaces.append(JavaOFInterface(class_name, version_map))
176
Andreas Wundsambe168f72013-08-03 22:49:35 -0700177 interfaces = [ i for i in interfaces if i.name not in self.interface_blacklist ]
178
Andreas Wundsam27303462013-07-16 12:52:35 -0700179 return interfaces
180
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700181 @memoize
182 def interface_by_name(self, name):
183 return find(lambda i: erase_type_annotation(i.name) == erase_type_annotation(name), self.interfaces)
184
Andreas Wundsam27303462013-07-16 12:52:35 -0700185 @property
186 @memoize
Andreas Wundsam001b1822013-08-02 22:25:55 -0700187 def all_classes(self):
188 return [clazz for interface in self.interfaces for clazz in interface.versioned_classes]
189
190 @property
191 @memoize
Andreas Wundsam27303462013-07-16 12:52:35 -0700192 def enums(self):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700193 name_version_enum_map = OrderedDefaultDict(lambda: OrderedDict())
Andreas Wundsam27303462013-07-16 12:52:35 -0700194
195 for version in self.versions:
196 of_protocol = of_g.ir[version.int_version]
197 for enum in of_protocol.enums:
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700198 name_version_enum_map[enum.name][version] = enum
Andreas Wundsam27303462013-07-16 12:52:35 -0700199
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700200 enums = [ JavaEnum(name, version_enum_map) for name, version_enum_map,
201 in name_version_enum_map.items() ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700202
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700203 # inelegant - need java name here
204 enums = [ enum for enum in enums if enum.name not in self.enum_blacklist ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700205 return enums
206
207 @memoize
208 def enum_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700209 res = find(lambda e: e.name == name, self.enums)
210 if not res:
Andreas Wundsam27303462013-07-16 12:52:35 -0700211 raise KeyError("Could not find enum with name %s" % name)
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700212 return res
Andreas Wundsam27303462013-07-16 12:52:35 -0700213
Andreas Wundsam5204de22013-07-30 11:34:45 -0700214 @property
215 @memoize
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700216 def of_factories(self):
Yotam Harchol791e4882013-09-05 16:32:56 -0700217 prefix = "org.projectfloodlight.openflow.protocol"
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700218
219 factories = OrderedDict()
220
221 sub_factory_classes = ("OFAction", "OFInstruction", "OFMeterBand", "OFOxm", "OFQueueProp")
222 for base_class in sub_factory_classes:
223 package = base_class[2:].lower()
224 remove_prefix = base_class[2].lower() + base_class[3:]
225
226 # HACK need to have a better way to deal with parameterized base classes
227 annotated_base_class = base_class + "<?>" if base_class == "OFOxm" else base_class
228
229 factories[base_class] = OFFactory(package="%s.%s" % (prefix, package),
230 name=base_class + "s", members=[], remove_prefix=remove_prefix, base_class=annotated_base_class, sub_factories={})
231
232 factories[""] = OFFactory(
233 package=prefix,
Andreas Wundsam5204de22013-07-30 11:34:45 -0700234 name="OFFactory",
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700235 remove_prefix="",
236 members=[], base_class="OFMessage", sub_factories=OrderedDict(
237 ("{}{}s".format(n[2].lower(), n[3:]), "{}s".format(n)) for n in sub_factory_classes ))
238
239 for i in self.interfaces:
240 for n, factory in factories.items():
241 if n == "":
242 factory.members.append(i)
243 break
244 else:
245 super_class = self.interface_by_name(n)
246 if i.is_instance_of(super_class):
247 factory.members.append(i)
248 break
249 return factories.values()
Andreas Wundsam5204de22013-07-30 11:34:45 -0700250
251 def generate_class(self, clazz):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700252 """ return wether or not to generate implementation class clazz.
253 Now true for everything except OFTableModVer10.
254 @param clazz JavaOFClass instance
255 """
Andreas Wundsam43526532013-08-01 22:03:50 -0700256 if clazz.interface.name.startswith("OFMatchV"):
257 return True
Andreas Wundsam001b1822013-08-02 22:25:55 -0700258 elif clazz.name == "OFTableModVer10":
259 # tablemod ver 10 is a hack and has no oftype defined
260 return False
Andreas Wundsam5204de22013-07-30 11:34:45 -0700261 if loxi_utils.class_is_message(clazz.interface.c_name):
262 return True
263 if loxi_utils.class_is_oxm(clazz.interface.c_name):
264 return True
Andreas Wundsam43526532013-08-01 22:03:50 -0700265 if loxi_utils.class_is_action(clazz.interface.c_name):
266 return True
267 if loxi_utils.class_is_instruction(clazz.interface.c_name):
268 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700269 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700270 return True
Andreas Wundsam5204de22013-07-30 11:34:45 -0700271
272
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700273class OFFactory(namedtuple("OFFactory", ("package", "name", "members", "remove_prefix", "base_class", "sub_factories"))):
Andreas Wundsam5204de22013-07-30 11:34:45 -0700274 @property
275 def factory_classes(self):
276 return [ OFFactoryClass(
Yotam Harchol791e4882013-09-05 16:32:56 -0700277 package="org.projectfloodlight.openflow.protocol.ver{}".format(version.of_version),
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700278 name="{}Ver{}".format(self.name, version.of_version),
Andreas Wundsam5204de22013-07-30 11:34:45 -0700279 interface=self,
280 version=version
281 ) for version in model.versions ]
282
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700283 def method_name(self, member, builder=True):
284 n = member.variable_name
285 if n.startswith(self.remove_prefix):
286 n = n[len(self.remove_prefix):]
287 n = n[0].lower() + n[1:]
288 if builder:
289 return "build" + n[0].upper() + n[1:]
290 else:
291 return n
Andreas Wundsam5204de22013-07-30 11:34:45 -0700292
293OFGenericClass = namedtuple("OFGenericClass", ("package", "name"))
Andreas Wundsame0d52be2013-08-22 07:52:13 -0700294class OFFactoryClass(namedtuple("OFFactoryClass", ("package", "name", "interface", "version"))):
295 @property
296 def base_class(self):
297 return self.interface.base_class
298
299 @property
300 def versioned_base_class(self):
301 base_class_interface = model.interface_by_name(self.interface.base_class)
302 if base_class_interface and base_class_interface.has_version(self.version):
303 return base_class_interface.versioned_class(self.version)
304 else:
305 return None
Andreas Wundsam5204de22013-07-30 11:34:45 -0700306
Andreas Wundsam27303462013-07-16 12:52:35 -0700307model = JavaModel()
308
309#######################################################################
310### OFVersion
311#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700312
313class JavaOFVersion(object):
314 """ Models a version of OpenFlow. contains methods to convert the internal
315 Loxi version to a java constant / a string """
316 def __init__(self, int_version):
317 self.int_version = int(int_version)
318
319 @property
320 def of_version(self):
321 return "1" + str(int(self.int_version) - 1)
322
323 @property
324 def constant_version(self):
325 return "OF_" + self.of_version
326
Andreas Wundsam27303462013-07-16 12:52:35 -0700327 def __repr__(self):
328 return "JavaOFVersion(%d)" % self.int_version
329
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700330 def __str__(self):
331 return of_g.param_version_names[self.int_version]
332
Andreas Wundsam27303462013-07-16 12:52:35 -0700333 def __hash__(self):
334 return hash(self.int_version)
335
336 def __eq__(self, other):
337 if other is None or type(self) != type(other):
338 return False
339 return (self.int_version,) == (other.int_version,)
340
341#######################################################################
342### Interface
343#######################################################################
344
345class JavaOFInterface(object):
346 """ Models an OpenFlow Message class for the purpose of the java class.
347 Version agnostic, in contrast to the loxi_ir python model.
348 """
349 def __init__(self, c_name, version_map):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700350 """"
351 @param c_name: loxi style name (e.g., of_flow_add)
352 @param version_map map of { JavaOFVersion: OFClass (from loxi_ir) }
353 """
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700354 self.c_name = c_name
Andreas Wundsam27303462013-07-16 12:52:35 -0700355 self.version_map = version_map
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700356 # name: the Java Type name, e.g., OFFlowAdd
Andreas Wundsam001b1822013-08-02 22:25:55 -0700357 self.name = java_type.name_c_to_caps_camel(c_name) if c_name != "of_header" else "OFMessage"
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700358 # variable_name name to use for variables of this type. i.e., flowAdd
Andreas Wundsam5204de22013-07-30 11:34:45 -0700359 self.variable_name = self.name[2].lower() + self.name[3:]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700360 self.title_name = self.variable_name[0].upper() + self.variable_name[1:]
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700361 # name for use in constants: FLOW_ADD
Andreas Wundsam27303462013-07-16 12:52:35 -0700362 self.constant_name = c_name.upper().replace("OF_", "")
363
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700364 pck_suffix, parent_interface, self.type_annotation = self.class_info()
Yotam Harchol791e4882013-09-05 16:32:56 -0700365 self.package = "org.projectfloodlight.openflow.protocol.%s" % pck_suffix if pck_suffix else "org.projectfloodlight.openflow.protocol"
Andreas Wundsam27303462013-07-16 12:52:35 -0700366 if self.name != parent_interface:
367 self.parent_interface = parent_interface
368 else:
369 self.parent_interface = None
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700370
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700371 @property
372 @memoize
373 def all_parent_interfaces(self):
374 return [ "OFObject" ] + \
375 ([ self.parent_interface ] if self.parent_interface else [] )+ \
376 self.additional_parent_interfaces
377 @property
378 @memoize
379 def additional_parent_interfaces(self):
380 if loxi_utils.class_is_message(self.c_name) and not self.is_virtual:
381 m = re.match(r'(.*)Request$', self.name)
382 if m:
383 reply_name = m.group(1) + "Reply"
384 if model.interface_by_name(reply_name):
385 return ["OFRequest<%s>" % reply_name ]
386 return []
387
388
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700389 def is_instance_of(self, other_class):
390 if self == other_class:
391 return True
392 parent = self.super_class
393 if parent is None:
394 return False
395 else:
396 return parent.is_instance_of(other_class)
397
398 @property
399 def super_class(self):
400 if not self.parent_interface:
401 return None
402 else:
403 return model.interface_by_name(self.parent_interface)
404
405
406 def inherited_declaration(self, type_spec="?"):
407 if self.type_annotation:
408 return "%s<%s>" % (self.name, type_spec)
409 else:
410 return "%s" % self.name
411
412 @property
413 def type_variable(self):
414 if self.type_annotation:
415 return "<T>"
416 else:
417 return "";
418
Andreas Wundsam27303462013-07-16 12:52:35 -0700419 def class_info(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700420 """ return tuple of (package_prefix, parent_class) for the current JavaOFInterface"""
421 # FIXME: This duplicates inheritance information that is now available in the loxi_ir
422 # model (note, that the loxi model is on versioned classes). Should check/infer the
423 # inheritance information from the versioned lox_ir classes.
Andreas Wundsam001b1822013-08-02 22:25:55 -0700424 if re.match(r'OF.+StatsRequest$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700425 return ("", "OFStatsRequest", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700426 elif re.match(r'OF.+StatsReply$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700427 return ("", "OFStatsReply", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700428 elif re.match(r'OFFlow(Add|Modify(Strict)?|Delete(Strict)?)$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700429 return ("", "OFFlowMod", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700430 elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFBsn.+$', self.name) and self.name != "OFBsnHeader":
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700431 return ("", "OFBsnHeader", None)
Andreas Wundsama705c6b2013-09-04 11:21:09 -0700432 elif loxi_utils.class_is_message(self.c_name) and re.match(r'OFNicira.+$', self.name) and self.name != "OFNiciraHeader":
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700433 return ("", "OFNiciraHeader", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700434 elif self.name == "OFBsnHeader" or self.name =="OFNiciraHeader":
435 return ("", "OFExperimenter", None)
Andreas Wundsam43526532013-08-01 22:03:50 -0700436 elif re.match(r'OFMatch.*', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700437 return ("", "Match", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700438 elif loxi_utils.class_is_message(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700439 return ("", "OFMessage", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700440 elif loxi_utils.class_is_action(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700441 if re.match(r'OFActionBsn.+', self.name):
442 return ("action", "OFActionBsn", None)
443 elif re.match(r'OFActionNicira.+', self.name):
444 return ("action", "OFActionNicira", None)
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700445 elif self.name == "OFActionBsn" or self.name == "OFActionNicira":
446 return ("action", "OFActionExperimenter", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700447 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700448 return ("action", "OFAction", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700449 elif re.match(r'OFBsnVport.+$', self.name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700450 return ("", "OFBsnVport", None)
451 elif self.name == "OFOxm":
452 return ("oxm", None, "T extends OFValueType<T>")
Andreas Wundsam5204de22013-07-30 11:34:45 -0700453 elif loxi_utils.class_is_oxm(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700454 if self.name in model.oxm_map:
455 return ("oxm", "OFOxm<%s>" % model.oxm_map[self.name].type_name, None)
456 else:
457 return ("oxm", "OFOxm", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700458 elif loxi_utils.class_is_instruction(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700459 return ("instruction", "OFInstruction", None)
Andreas Wundsam5204de22013-07-30 11:34:45 -0700460 elif loxi_utils.class_is_meter_band(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700461 return ("meterband", "OFMeterBand", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700462 elif loxi_utils.class_is_queue_prop(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700463 return ("queueprop", "OFQueueProp", None)
Andreas Wundsam001b1822013-08-02 22:25:55 -0700464 elif loxi_utils.class_is_hello_elem(self.c_name):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700465 return ("", "OFHelloElem", None)
Andreas Wundsam27303462013-07-16 12:52:35 -0700466 else:
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700467 return ("", None, None)
468
469 @property
470 @memoize
471 def writeable_members(self):
472 return [ m for m in self.members if m.is_writeable ]
Andreas Wundsam27303462013-07-16 12:52:35 -0700473
474 @property
475 @memoize
476 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700477 return self.ir_model_members + self.virtual_members
478
479 @property
480 @memoize
481 def ir_model_members(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700482 """return a list of all members to be exposed by this interface. Corresponds to
483 the union of the members of the vesioned classes without length, fieldlength
484 and pads (those are handled automatically during (de)serialization and not exposed"""
Andreas Wundsam27303462013-07-16 12:52:35 -0700485 all_versions = []
486 member_map = collections.OrderedDict()
487
488 for (version, of_class) in self.version_map.items():
489 for of_member in of_class.members:
490 if isinstance(of_member, OFLengthMember) or \
491 isinstance(of_member, OFFieldLengthMember) or \
492 isinstance(of_member, OFPadMember):
493 continue
494 if of_member.name not in member_map:
495 member_map[of_member.name] = JavaMember.for_of_member(self, of_member)
496
Andreas Wundsamb1da3f62013-09-04 18:46:03 -0700497 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 -0700498
499 @property
500 def virtual_members(self):
501 if self.name == "OFOxm":
502 return (
503 JavaVirtualMember(self, "value", java_type.generic_t),
504 JavaVirtualMember(self, "mask", java_type.generic_t),
505 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype("T")),
506 JavaVirtualMember(self, "masked", java_type.boolean),
507 )
508 elif self.parent_interface and self.parent_interface.startswith("OFOxm"):
509 field_type = java_type.make_match_field_jtype(model.oxm_map[self.name].type_name) \
510 if self.name in model.oxm_map \
511 else java_type.make_match_field_jtype()
512
513 return (
514 JavaVirtualMember(self, "matchField", field_type),
515 JavaVirtualMember(self, "masked", java_type.boolean),
516 ) \
517 + \
518 (
519 ( JavaVirtualMember(self, "mask", find(lambda x: x.name == "value", self.ir_model_members).java_type), ) if not find(lambda x: x.name == "mask", self.ir_model_members) else
520 ()
521 )
522 else:
523 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700524
525 @property
526 @memoize
527 def is_virtual(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700528 """ Is this interface virtual. If so, do not generate a builder interface """
Andreas Wundsam001b1822013-08-02 22:25:55 -0700529 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 -0700530
531 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700532 def is_universal(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700533 """ Is this interface universal, i.e., does it exist in all OF versions? """
Andreas Wundsam5204de22013-07-30 11:34:45 -0700534 return len(self.all_versions) == len(model.versions)
535
536 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700537 @memoize
538 def all_versions(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700539 """ return list of all versions that this interface exists in """
Andreas Wundsam27303462013-07-16 12:52:35 -0700540 return self.version_map.keys()
541
Andreas Wundsam5204de22013-07-30 11:34:45 -0700542 def has_version(self, version):
543 return version in self.version_map
544
Andreas Wundsam27303462013-07-16 12:52:35 -0700545 def versioned_class(self, version):
546 return JavaOFClass(self, version, self.version_map[version])
547
548 @property
549 @memoize
550 def versioned_classes(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700551 return [ self.versioned_class(version) for version in self.all_versions ]
552
553#######################################################################
554### (Versioned) Classes
555#######################################################################
556
557class JavaOFClass(object):
558 """ Models an OpenFlow Message class for the purpose of the java class.
Andreas Wundsamd40ddbf2013-07-25 15:40:47 -0700559 Version specific child of a JavaOFInterface
Andreas Wundsam27303462013-07-16 12:52:35 -0700560 """
561 def __init__(self, interface, version, ir_class):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700562 """
563 @param interface JavaOFInterface instance of the parent interface
564 @param version JavaOFVersion
565 @param ir_class OFClass from loxi_ir
566 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700567 self.interface = interface
568 self.ir_class = ir_class
569 self.c_name = self.ir_class.name
570 self.version = version
571 self.constant_name = self.c_name.upper().replace("OF_", "")
Yotam Harchol791e4882013-09-05 16:32:56 -0700572 self.package = "org.projectfloodlight.openflow.protocol.ver%s" % version.of_version
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700573 self.generated = False
574
575 @property
576 @memoize
577 def unit_test(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700578 return JavaUnitTestSet(self)
Andreas Wundsam27303462013-07-16 12:52:35 -0700579
580 @property
581 def name(self):
582 return "%sVer%s" % (self.interface.name, self.version.of_version)
583
584 @property
Andreas Wundsam5204de22013-07-30 11:34:45 -0700585 def variable_name(self):
586 return self.name[3:]
587
588 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700589 def length(self):
590 if self.is_fixed_length:
591 return self.min_length
592 else:
593 raise Exception("No fixed length for class %s, version %s" % (self.name, self.version))
594
595 @property
596 def min_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700597 """ @return the minimum wire length of an instance of this class in bytes """
Andreas Wundsam27303462013-07-16 12:52:35 -0700598 id_tuple = (self.ir_class.name, self.version.int_version)
599 return of_g.base_length[id_tuple] if id_tuple in of_g.base_length else -1
600
601 @property
602 def is_fixed_length(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700603 """ true iff this class serializes to a fixed length on the wire """
Andreas Wundsambbf85e12013-09-13 14:18:01 -0700604 return (self.ir_class.name, self.version.int_version) in of_g.is_fixed_length and \
605 not self.is_virtual
Andreas Wundsam27303462013-07-16 12:52:35 -0700606
607 def all_properties(self):
608 return self.interface.members
609
610 def get_member(self, name):
611 for m in self.members:
612 if m.name == name:
613 return m
614
615 @property
616 @memoize
617 def data_members(self):
618 return [ prop for prop in self.members if prop.is_data ]
619
620 @property
621 @memoize
622 def fixed_value_members(self):
623 return [ prop for prop in self.members if prop.is_fixed_value ]
624
625 @property
626 @memoize
627 def public_members(self):
628 return [ prop for prop in self.members if prop.is_public ]
629
630 @property
631 @memoize
632 def members(self):
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700633 return self.ir_model_members + self.virtual_members
634
635 @property
636 def ir_model_members(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700637 members = [ JavaMember.for_of_member(self, of_member) for of_member in self.ir_class.members ]
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700638 return tuple(members)
639
640 @property
641 def virtual_members(self):
642 if self.interface.parent_interface and self.interface.parent_interface.startswith("OFOxm"):
643 if self.interface.name in model.oxm_map:
644 oxm_entry = model.oxm_map[self.interface.name]
645 return (
646 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(oxm_entry.type_name), "MatchField.%s" % oxm_entry.value),
647 JavaVirtualMember(self, "masked", java_type.boolean, "true" if oxm_entry.masked else "false"),
648 )
649 else:
650 return (
651 JavaVirtualMember(self, "matchField", java_type.make_match_field_jtype(), "null"),
652 JavaVirtualMember(self, "masked", java_type.boolean, "false"),
653 )
654 else:
655 return ()
Andreas Wundsam27303462013-07-16 12:52:35 -0700656
657 def all_versions(self):
658 return [ JavaOFVersion(int_version)
659 for int_version in of_g.unified[self.c_name]
660 if int_version != 'union' and int_version != 'object_id' ]
661
662 def version_is_inherited(self, version):
663 return 'use_version' in of_g.unified[self.ir_class.name][version.int_version]
664
665 def inherited_from(self, version):
666 return JavaOFVersion(of_g.unified[self.ir_class.name][version.int_version]['use_version'])
667
668 @property
669 def is_virtual(self):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700670 return self.ir_class.virtual # type_maps.class_is_virtual(self.c_name) or self.ir_class.virtual
671
672 @property
673 def discriminator(self):
674 return find(lambda m: isinstance(m, OFDiscriminatorMember), self.ir_class.members)
Andreas Wundsam27303462013-07-16 12:52:35 -0700675
676 @property
677 def is_extension(self):
678 return type_maps.message_is_extension(self.c_name, -1)
679
Andreas Wundsam758c9cc2013-08-01 22:16:06 -0700680 @property
681 def align(self):
682 return int(self.ir_class.params['align']) if 'align' in self.ir_class.params else 0
683
Andreas Wundsam1f0d8802013-08-02 22:20:14 -0700684 @property
685 @memoize
686 def superclass(self):
687 return find(lambda c: c.version == self.version and c.c_name == self.ir_class.superclass, model.all_classes)
688
689 @property
690 @memoize
691 def subclasses(self):
692 return [ c for c in model.all_classes if c.version == self.version and c.ir_class.superclass == self.c_name ]
693
Andreas Wundsam27303462013-07-16 12:52:35 -0700694#######################################################################
695### Member
696#######################################################################
697
698
699class JavaMember(object):
700 """ Models a property (member) of an openflow class. """
701 def __init__(self, msg, name, java_type, member):
702 self.msg = msg
703 self.name = name
704 self.java_type = java_type
705 self.member = member
706 self.c_name = self.member.name if(hasattr(self.member, "name")) else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700707
708 @property
709 def title_name(self):
710 return self.name[0].upper() + self.name[1:]
711
712 @property
713 def constant_name(self):
714 return self.c_name.upper()
715
716 @property
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700717 def getter_name(self):
718 return ("is" if self.java_type.public_type == "boolean" else "get") + self.title_name
719
720 @property
721 def setter_name(self):
722 return "set" + self.title_name
723
724 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700725 def default_name(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700726 if self.is_fixed_value:
727 return self.constant_name
728 else:
729 return "DEFAULT_"+self.constant_name
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700730
731 @property
732 def default_value(self):
733 java_type = self.java_type.public_type;
734
Andreas Wundsam27303462013-07-16 12:52:35 -0700735 if self.is_fixed_value:
736 return self.enum_value
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700737 elif java_type == "OFOxmList":
738 return "OFOxmList.EMPTY"
Andreas Wundsam27303462013-07-16 12:52:35 -0700739 elif re.match(r'List.*', java_type):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700740 return "Collections.emptyList()"
741 elif java_type == "boolean":
742 return "false";
Andreas Wundsam880a2a82013-08-22 07:55:14 -0700743 elif self.java_type.is_array:
744 return "new %s[0]" % java_type[:-2]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700745 elif java_type in ("byte", "char", "short", "int", "long"):
746 return "({0}) 0".format(java_type);
747 else:
748 return "null";
749
750 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700751 def enum_value(self):
752 if self.name == "version":
753 return "OFVersion.%s" % self.msg.version.constant_version
754
755 java_type = self.java_type.public_type;
756 try:
757 global model
758 enum = model.enum_by_name(java_type)
759 entry = enum.entry_by_version_value(self.msg.version, self.value)
760 return "%s.%s" % ( enum.name, entry.name)
761 except KeyError, e:
762 print e.message
763 return self.value
764
765 @property
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700766 def is_pad(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700767 return isinstance(self.member, OFPadMember)
768
769 def is_type_value(self, version=None):
770 if(version==None):
771 return any(self.is_type_value(version) for version in self.msg.all_versions)
772 try:
773 return self.c_name in get_type_values(self.msg.c_name, version.int_version)
774 except:
775 return False
776
777 @property
778 def is_field_length_value(self):
779 return isinstance(self.member, OFFieldLengthMember)
780
781 @property
Andreas Wundsam001b1822013-08-02 22:25:55 -0700782 def is_discriminator(self):
783 return isinstance(self.member, OFDiscriminatorMember)
784
785 @property
Andreas Wundsam27303462013-07-16 12:52:35 -0700786 def is_length_value(self):
787 return isinstance(self.member, OFLengthMember)
788
789 @property
790 def is_public(self):
791 return not (self.is_pad or self.is_length_value)
792
793 @property
794 def is_data(self):
795 return isinstance(self.member, OFDataMember) and self.name != "version"
796
797 @property
798 def is_fixed_value(self):
799 return hasattr(self.member, "value") or self.name == "version" \
800 or ( self.name == "length" and self.msg.is_fixed_length) \
801 or ( self.name == "len" and self.msg.is_fixed_length)
802
803 @property
804 def value(self):
805 if self.name == "version":
806 return self.msg.version.int_version
807 elif self.name == "length" or self.name == "len":
808 return self.msg.length
Andreas Wundsam27303462013-07-16 12:52:35 -0700809 else:
Andreas Wundsam001b1822013-08-02 22:25:55 -0700810 return self.java_type.format_value(self.member.value)
811
812 @property
813 def priv_value(self):
814 if self.name == "version":
815 return self.msg.version.int_version
816 elif self.name == "length" or self.name == "len":
817 return self.msg.length
818 else:
819 return self.java_type.format_value(self.member.value, pub_type=False)
820
Andreas Wundsam27303462013-07-16 12:52:35 -0700821
822 @property
823 def is_writeable(self):
824 return self.is_data and not self.name in model.write_blacklist[self.msg.name]
825
826 def get_type_value_info(self, version):
827 return get_type_values(msg.c_name, version.int_version)[self.c_name]
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700828
829 @property
830 def length(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700831 if hasattr(self.member, "length"):
832 return self.member.length
833 else:
Andreas Wundsam5204de22013-07-30 11:34:45 -0700834 count, base = loxi_utils.type_dec_to_count_base(self.member.type)
Andreas Wundsam27303462013-07-16 12:52:35 -0700835 return of_g.of_base_types[base]['bytes'] * count
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700836
837 @staticmethod
Andreas Wundsam27303462013-07-16 12:52:35 -0700838 def for_of_member(java_class, member):
839 if isinstance(member, OFPadMember):
840 return JavaMember(None, "", None, member)
841 else:
842 if member.name == 'len':
843 name = 'length'
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700844 elif member.name == 'value_mask':
845 name = 'mask'
Andreas Wundsam27303462013-07-16 12:52:35 -0700846 else:
847 name = java_type.name_c_to_camel(member.name)
848 j_type = java_type.convert_to_jtype(java_class.c_name, member.name, member.oftype)
849 return JavaMember(java_class, name, j_type, member)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700850
851 @property
852 def is_universal(self):
Andreas Wundsam27303462013-07-16 12:52:35 -0700853 if not self.msg.c_name in of_g.unified:
854 print("%s not self.unified" % self.msg.c_name)
855 return False
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700856 for version in of_g.unified[self.msg.c_name]:
857 if version == 'union' or version =='object_id':
858 continue
859 if 'use_version' in of_g.unified[self.msg.c_name][version]:
860 continue
861
Andreas Wundsam27303462013-07-16 12:52:35 -0700862 if not self.member.name in (f['name'] for f in of_g.unified[self.msg.c_name][version]['members']):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700863 return False
864 return True
865
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700866 @property
867 def is_virtual(self):
868 return False
869
Andreas Wundsam27303462013-07-16 12:52:35 -0700870 def __hash__(self):
871 return hash(self.name)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700872
Andreas Wundsam27303462013-07-16 12:52:35 -0700873 def __eq__(self, other):
874 if other is None or type(self) != type(other):
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700875 return False
Andreas Wundsam27303462013-07-16 12:52:35 -0700876 return (self.name,) == (other.name,)
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700877
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700878class JavaVirtualMember(JavaMember):
879 """ Models a virtual property (member) of an openflow class that is not backed by a loxi ir member """
880 def __init__(self, msg, name, java_type, value=None):
881 JavaMember.__init__(self, msg, name, java_type, member=None)
882 self._value = value
883
884 @property
885 def is_fixed_value(self):
886 return True
887
888 @property
889 def value(self):
890 return self._value
891
892 @property
893 def priv_value(self):
894 return self._value
895
896
897 @property
898 def is_universal(self):
899 return True
900
901 @property
902 def is_virtual(self):
903 return True
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700904
905#######################################################################
906### Unit Test
907#######################################################################
908
Yotam Harchol466b3212013-08-15 12:14:46 -0700909class JavaUnitTestSet(object):
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700910 def __init__(self, java_class):
911 self.java_class = java_class
Yotam Harchol466b3212013-08-15 12:14:46 -0700912 first_data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700913 name=java_class.c_name[3:])
Yotam Harchol466b3212013-08-15 12:14:46 -0700914 data_file_template = "of{version}/{name}.".format(version=java_class.version.of_version,
915 name=java_class.c_name[3:]) + "{i}.data"
916 test_class_name = self.java_class.name + "Test"
917 self.test_units = []
918 if test_data.exists(first_data_file_name):
919 self.test_units.append(JavaUnitTest(java_class, first_data_file_name, test_class_name))
920 i = 1
921 while test_data.exists(data_file_template.format(i=i)):
922 self.test_units.append(JavaUnitTest(java_class, data_file_template.format(i=i), test_class_name + str(i)))
923 i = i + 1
924
925 @property
926 def package(self):
927 return self.java_class.package
928
929 @property
930 def has_test_data(self):
931 return len(self.test_units) > 0
932
933 @property
934 def length(self):
935 return len(self.test_units)
936
937 def get_test_unit(self, i):
938 return self.test_units[i]
939
940
941class JavaUnitTest(object):
942 def __init__(self, java_class, file_name=None, test_class_name=None):
943 self.java_class = java_class
944 if file_name is None:
945 self.data_file_name = "of{version}/{name}.data".format(version=java_class.version.of_version,
946 name=java_class.c_name[3:])
947 else:
948 self.data_file_name = file_name
949 if test_class_name is None:
950 self.test_class_name = self.java_class.name + "Test"
951 else:
952 self.test_class_name = test_class_name
953
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700954 @property
955 def package(self):
956 return self.java_class.package
957
958 @property
959 def name(self):
Yotam Harchol466b3212013-08-15 12:14:46 -0700960 return self.test_class_name
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700961
962 @property
963 def has_test_data(self):
964 return test_data.exists(self.data_file_name)
965
966 @property
967 @memoize
968 def test_data(self):
969 return test_data.read(self.data_file_name)
970
971
Andreas Wundsam27303462013-07-16 12:52:35 -0700972#######################################################################
973### Enums
974#######################################################################
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700975
Andreas Wundsam27303462013-07-16 12:52:35 -0700976class JavaEnum(object):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700977 def __init__(self, c_name, version_enum_map):
Andreas Wundsam27303462013-07-16 12:52:35 -0700978 self.c_name = c_name
Andreas Wundsambe168f72013-08-03 22:49:35 -0700979
980 if c_name == "of_stats_types":
981 self.name = "OFStatsType"
982 else:
983 self.name = "OF" + java_type.name_c_to_caps_camel("_".join(c_name.split("_")[1:]))
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700984
Andreas Wundsam27303462013-07-16 12:52:35 -0700985 # Port_features has constants that start with digits
986 self.name_prefix = "PF_" if self.name == "OFPortFeatures" else ""
Andreas Wundsam40e14f72013-05-06 14:49:08 -0700987
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700988 self.version_enums = version_enum_map
989
990 entry_name_version_value_map = OrderedDefaultDict(lambda: OrderedDict())
991 for version, ir_enum in version_enum_map.items():
992 for ir_entry in ir_enum.entries:
993 if "virtual" in ir_entry.params:
994 continue
995 entry_name_version_value_map[ir_entry.name][version] = ir_entry.value
996
Andreas Wundsam27303462013-07-16 12:52:35 -0700997 self.entries = [ JavaEnumEntry(self, name, version_value_map)
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700998 for (name, version_value_map) in entry_name_version_value_map.items() ]
Andreas Wundsam43526532013-08-01 22:03:50 -0700999
1000 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 -07001001 self.package = "org.projectfloodlight.openflow.protocol"
Andreas Wundsam40e14f72013-05-06 14:49:08 -07001002
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001003 self.metadata = model.enum_metadata_map[self.name]
1004
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001005 def wire_type(self, version):
1006 ir_enum = self.version_enums[version]
1007 if "wire_type" in ir_enum.params:
1008 return java_type.convert_enum_wire_type_to_jtype(ir_enum.params["wire_type"])
1009 else:
1010 return java_type.u8
1011
1012 @property
1013 def versions(self):
1014 return self.version_enums.keys()
1015
Andreas Wundsam27303462013-07-16 12:52:35 -07001016 @memoize
1017 def entry_by_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001018 res = find(lambda e: e.name == name, self.entries)
1019 if res:
1020 return res
1021 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001022 raise KeyError("Enum %s: no entry with name %s" % (self.name, name))
1023
1024 @memoize
1025 def entry_by_c_name(self, name):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001026 res = find(lambda e: e.c_name == name, self.entries)
1027 if res:
1028 return res
1029 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001030 raise KeyError("Enum %s: no entry with c_name %s" % (self.name, name))
1031
1032 @memoize
1033 def entry_by_version_value(self, version, value):
Andreas Wundsam1f0d8802013-08-02 22:20:14 -07001034 res = find(lambda e: e.values[version] == value if version in e.values else False, self.entries)
1035 if res:
1036 return res
1037 else:
Andreas Wundsam27303462013-07-16 12:52:35 -07001038 raise KeyError("Enum %s: no entry with version %s, value %s" % (self.name, version, value))
1039
1040# values: Map JavaVersion->Value
1041class JavaEnumEntry(object):
1042 def __init__(self, enum, name, values):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001043 self.enum = enum
Andreas Wundsam27303462013-07-16 12:52:35 -07001044 self.name = enum.name_prefix + "_".join(name.split("_")[1:]).upper()
1045 self.values = values
1046
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -07001047 @property
1048 def constructor_params(self):
1049 return [ m.value(self) for m in self.enum.metadata ]
1050
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001051 def has_value(self, version):
1052 return version in self.values
1053
Andreas Wundsam27303462013-07-16 12:52:35 -07001054 def value(self, version):
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -07001055 return self.values[version]
1056
1057 def format_value(self, version):
1058 res = self.enum.wire_type(version).format_value(self.values[version])
Andreas Wundsam27303462013-07-16 12:52:35 -07001059 return res
1060
Andreas Wundsam27303462013-07-16 12:52:35 -07001061 def all_values(self, versions, not_present=None):
1062 return [ self.values[version] if version in self.values else not_present for version in versions ]